从零理解 GCC/G++:编译原理
1. 先有编译器还是先有语言?
这个问题像极了“先有鸡还是先有蛋”的哲学思辨,但答案其实很明确:先有编译器,再有编程语言。
追溯计算机发展的源头,早期机器只能理解二进制指令,对应的编译器自然也是二进制的。人们先用这种原始的二进制编译器写出汇编语言,再基于汇编语言开发出能编译汇编代码的编译器——这个编译器的底层实现仍是二进制,但它的诞生让汇编语言得以被机器解读。这一过程,就是计算机领域著名的“语言/编译器自举”(简单说,就是用一门语言的早期版本,逐步构建出能编译这门语言的成熟工具)。
以C语言的诞生为例,这个过程会更清晰:
- 先用汇编语言编写一个“翻译器”,它能把C语言代码转换成汇编代码(这就是最早的C语言编译器);
- 再用C语言本身重新编写这个编译器——此时,成熟的C语言编译器已经能直接编译C语言代码,形成了“用C语言编译C语言”的闭环,完成了自举。
这种自举机制堪称编程语言发展的“基建工程”,它让一门语言能脱离底层汇编的束缚,实现自我迭代与进化。
2. 背景知识
- 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等)
- 编译(⽣成汇编)
- 汇编(⽣成机器可识别代码)
- 链接(⽣成可执⾏⽂件或库⽂件)
3. gcc编译选项
gcc的语法如下
gcc -o 目标文件 源文件
“-o”代表指定输出文件名称,其后必须紧跟输出的目标文件
源文件可以在命令中的任意位置(-o前或后都可以)
3.1 预处理
gcc -E 源文件 -o 目标文件.i
“-E”代表执行完预处理就停止,生成的.i后缀文件即为预处理后的文件。
3.2 编译(生成汇编)
gcc -S 目标文件.i -o 目标文件.s
"-S"代表只进行编译不进行汇编,生成汇编代码
3.3 汇编(生成机器可识别的代码)
gcc -c 目标文件.s -o 目标文件.o
“-c”就可看到汇编代码已转化为“.o”的⼆进制⽬标代码了
3.4 连接(生成可执行程序)
gcc 目标文件.o -o 目标文件
4. 动态链接和静态链接
先来看这样的例子

4.1 动态链接:
开学前,老学长张三告诉准高中生小李,学校北门往东走有个网吧,放了学可以去那放松放松,小李非常高兴。一次周末,小李列出了今天要做的事情,其中就计划去网吧打会游戏。
在这个过程中,张三充当编译器,小李是可执行程序,网吧相当于动态库。张三在开学前告诉小李网吧的位置,这一行为类似编译器告诉可执行程序动态库的位置,小李(程序)始终记着网吧(动态库)位置。
4.2 静态链接:
网吧被家长举报了,小李周末去不了网吧了,但小李还想玩游戏。所以小李想了一招,他把最喜欢的那台电脑买回来放宿舍里了,这样想玩的时候就能随时玩。
在这个过程中,小李把电脑带回来的行为就类似把库放入程序中,将库的地址复制一份放入程序中。
4.3 优缺点
动态链接优点:省空间,可执行程序体积小
动态链接缺点:动态库丢失则所有程序都无法运行
静态链接优点:不依赖其他库,库丢失也没关系
静态链接缺点:程序体积大,比较浪费资源
4.4 file查看文件链接方式


在gcc -o code_static code.s -static
加上“-static”可以指定静态链接方式
4.5 yum glibc-static
云服务器默认没有按照C/C++标准静态库,搜“yumC/C++标准静态库“下载
sudo yum install -y glibc-static
1151

被折叠的 条评论
为什么被折叠?



