
欢迎拜访 :Madison-No7个人主页
文章主题:gcc/g++编辑器 && 初识动静态库 && 程序翻译过程
隶属专栏:从0到1掌握Linux
写作日期:2025年10月21号
目录
[4.1 什么是库?](#4.1 什么是库?)
[4.2 目标文件和库是如何链接的?](#4.2 目标文件和库是如何链接的?)
[4.2.1 静态链接:](#4.2.1 静态链接:)
[4.2.2 动态链接:](#4.2.2 动态链接:)
[4.3 动静态库的对比:](#4.3 动静态库的对比:)
前言:
我们使用 Vim 编辑器编写的代码只是文本文件,要让代码运行起来,就需要借助 gcc 和 g++ 编译器。这两个工具分别用于编译 C 和 C++ 程序。下面我将为大家介绍它们如何完成代码的编译过程。
gcc/g++编译选项:
格式 gcc/g++ [选项] 要编译的⽂件 [选项] [⽬标⽂件]
写好的test.c源文件:

该程序需要经过翻译过程生成可执行文件,才能执行代码。
也可以跳过翻译过程,直接生成可执行文件。

📌 翻译过程是由编译和链接两个大的过程组成,而编译又可分解成:预处理、编译、汇编三个过程。
一、预处理:

将test.c文件进行预处理,生成test.i预处理文件-----gcc --E test.c --o test.i
选项"-E":开始进程程序翻译,在预处理做完的时候,就停下来。
".i"⽂件为已经过预处理的C原始程序。
**选项"-o"**是指定写到test.i文件里面,如果不加选项-o,就直接打印到下面。
vim test.i -----打开test.i文件


预处理阶段的功能:
在预处理阶段,编译器会将头文件内容(头文件中只是一些函数的声明)展开并拷贝到test.i文件中,同时执行以下操作:去除注释、替换宏定义以及处理条件编译指令。
🌟条件编译的用途?
1.同一套代码可能需要支持不同功能版本(如社区版、专业版),或根据客户需求启用 / 禁用特定模块,条件编译可通过宏定义快速切换。
2.内核源代码也是采用条件编译进行动态裁剪。
- 开发工具,应用软件适配不同平台。
gcc test.c -o test -DM ------其中的-DM意思是#define M->插入到代码中,也就是说可以进行命令行级别的宏定义。
🌟预处理的本质:
让编译器编辑修改我们的代码,把不需要去掉,把需要的加上,但是还是C语言,只不过和我们的源码相比变得更干净了。
二、编译(生成汇编):

将预处理文件进行编译,生成汇编代码-----gcc -S test.i -o test.s
"-S"的作用是:开始生成汇编代码,生成完了,就停下来。
".s",常为汇编代码的后缀。
vim test.s ----打开test.s文件

编译阶段的功能:
gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作, 在检查⽆误后,gcc 把代码翻译成汇编语⾔。
📌 为什么C/C++编译,要先变成汇编代码?
首先要明白计算机的硬件核心只能识别二进制,这是由半导体电路的二态性决定的;其他进制(十进制、十六进制等)是为了方便人类使用而设计的 "抽象层",最终都会被转换为二进制信号才能被硬件处理。所以我们所写的程序,最后都要转化为机器语言(二进制)才能被计算机硬件处理。
三、汇编(生成机器可识别的代码):

将汇编文件转成目标文件(二进制)-----gcc -c test.s -o test.o
"-c":只进行编译(Compile),不进行链接(Link),最终生成目标文件(Object File)而非可执行文件。
".o":目标文件(Object File),是二进制文件
vim test.o

汇编的功能:
将汇编语言的.s文件转化为机器指令,生成后缀为.o(Windows 下为.obj)的目标文件。
**注意:**生成的目标文件是二进制文件,还不能直接运行,因为它缺少程序运行所需的外部资源,比如我们写的test.c源文件中用到了printf函数,汇编过程只是把我们写的代码转化成了机器指令,对于printf函数,它的定义是在C语言标准库里面,它并没有转化为机器指令,所以我们还要经过链接:将多个目标文件和所需的库文件组合,生成可执行文件(Windows 下为.exe,Linux 下为无后缀的可执行文件)。
📌 小Tips:
如何记忆gcc编译选项:-ESc 就是键盘左上角的按键Esc,只需要记住前两个字母是大写的。
如何记忆编译过程所形成的临时文件后缀:.iso 可以理解成镜像文件
四、链接(生成可执行文件或库文件):

链接的功能:
将多个目标文件(.o文件) 和所需的库文件组合到一起,生成可执行文件(Windows 下为.exe,Linux 下为无后缀的可执行文件)。
其实对于库文件无论是静态库还是动态库(共享库),本质上都是由多个目标文件(.o
文件)"打包" 组合而成的集合。关于如何"打包"形成库,以后会讲解到。

📌 我们往往喜欢的是把多个源文件编译成对应.o二进制文件,再把这些.o文件合并到一起,形成可执行文件。为什么呢?
因为对一个大型程序来说,可能有成百上千个.c源文件组成,如果直接编译成可执行文件,每次修改任意一个源文件 ,编译器都需要重新编译所有文件 ,这在文件数量多、代码量大时会极其耗时(例如一个包含 100 个文件的项目,改一行代码就要重新编译 100 个文件)。而先编译成.o目标文件时,只有被修改的源文件会重新编译,未修改的文件只需复用已生成的.o文件。最后通过链接器将所有.o文件组合成可执行文件,大幅减少重复劳动。这就像盖房子:先预制好门窗、墙体(.o文件),哪部分坏了只换哪部分,而不是每次都推倒重盖。
🌟上面提到了库文件,那什么是库文件呢?
库文件(Library File)是存储可复用代码(函数、类、数据结构等)的物理文件,是 "库" 这一抽象功能集合的具体载体。它包含编译后的二进制代码,供其他程序调用,以实现代码复用和功能扩展。
上面所写的test.c源文件,并没有定义**"printf"** 的函数实现,且在预编译中包含的"stdio.h" 中也只有该函数的声明,⽽没有定义函数的实现,那么,是在哪⾥实现**"printf"** 函数的呢? 答案是:系统把这些函数实现都被放到名为 libc.so.6 的库⽂件 中去了,在没有特别指定时,gcc 会到系统默认的搜索路径"/usr/lib "下进⾏查找,也就是链接到libc.so.6 库函数中去,这样就能实现函数**"printf"**了,而这也是链接的作⽤。

ldd + 可执行文件,可以查看可执行文件依赖了哪些库文件。

ldd +/usr/lib+指令,可以查看这些指令依赖了哪些库。通过上图可以看出ls、mkdir指令也依赖了libc.so.6库,也就是说Linux的指令也是由C语言写的。
🌟注意:
libc.so.6是 Linux 系统下的 C 语言标准库(GNU C Library,简称 glibc)的动态库文件,是绝大多数 Linux 程序运行的核心依赖。几乎所有 Linux 下的 C 程序(包括系统命令如 ls、mkdir)都依赖libc.so.6。如果这个文件损坏或丢失,系统会直接报错,甚至无法正常启动。
4.1 什么是库?
库(Library) 是一组预先编写好的代码集合,包含可复用的函数、类、数据结构或其他程序组件,目的是帮助开发者快速实现常见功能,避免重复造轮子,提高开发效率。
库分为静态库和动态库?
- 静态库是编译好的二进制代码集合,在程序编译的 "链接阶段" 会被完整复制到目标程序中,成为可执行文件的一部分。
- 动态库是独立存储的二进制代码文件 ,程序编译时不会被复制到可执行文件中,仅在程序运行时被加载到内存并供程序调用,多个程序可共享同一份动态库。
注意:
Linux下,动态库XXX.so, 静态库XXX.a
Windows下,动态库XXX.dll, 静态库XXX.lib
我们在命名自己所写的库时,比如写了一个xyz库,命名时要加上lib前缀,后缀(不同平台下不一样)。以Linux下为例,可命名为libxyz.so。
4.2 目标文件和库是如何链接的?
总体上,链接分为两类:动态链接 和静态链接。
4.2.1 静态链接:
把我们程序中使用的库方法,拷贝给我自己!静态库就像电脑商城,当有人有上网需求时,会到电脑商城去买一台专属的电脑,只供自己使用。此外静态库只有在链接时有用,一旦形成可执行程序,静态库可以不再需要了。

4.2.2 动态链接:
程序编译时,链接器仅在可执行文件中记录动态库的依赖信息 (如库文件名、函数名),不复制库代码;程序运行时 ,由操作系统加载动态库并解析函数地址。动态库就像是一个网吧,任何人想上网了,都可以去到这个网吧里。即:动态库是被所有程序所共享的,一般也被叫做共享库。这意味着,动态库只需要一个就够了,它可以满足所有程序的需求。

4.3 动静态库的对比:
1.动态库所形成的可执行程序体积一定很小。
2.可执行程序对静态库的依赖小,动态库不能缺失。
3.程序运行时,需要加载到内存,通过静态链接的程序,会在内存中出现大量重复的代码。
4.动态链接比较节省资源。
示例:
以test.c代码为例:

ldd test 查看依赖哪些库

所以gcc编辑器默认实行动态链接的。
file +可执行文件:查看具体可执行程序的信息。

同时动态链接形成的可执行文件大小:

如果非得要通过静态链接生成可执行文件:
需要在最后加上-static。



同时静态链接形成的可执行文件大小:

此外C++所以依赖的动态库是:libstdc++.so.6
再谈动态库:

动态库的代码段只需加载一份到内存,多个依赖它的可执行文件通过动态链接共享这份代码;动态库不能丢失,就像网吧被查封了,人们就不能去上网一样。一旦对应的动态库丢失,影响的不只是一个程序,可能会导致多个程序都无法正常运行。
完。
今天的分享就到这里,感谢各位大佬的关注,大家互相学习,共同进步呀!
