1.编译器gcc/g++
1.1C语言程序的翻译过程
1.预处理
在此阶段做的事情:
- 头文件展开:把我们编写的代码中的包含头文件的代码替换成头文件本身
- 删除所有的注释
- #define定义的符号和宏全部替换
- 执行条件编译
在Linux下,我们可以通过指令让gcc只执行预处理操作
gcc -E test.c -o test.i # -E 表示从现在开始,进行程序的翻译,当预处理结束时停下来 # -o 表示指明产生的文件的名称
可以看到经过预编译之后,#include包含头文件的代码没有了,但是文件中多了几百行,这些多的就是头文件的内容被拷贝进来了,注释部分被删除,宏定义被替换了,条件编译也转变成了执行过后的结果。
2.编译
此阶段做的事情:
- 语法分析
- 词法分析
- 语义分析
- 符号汇总
最终的结果就是把C语言代码变成汇编语言代码
在Linux下需要执行的指令是:
gcc -S test.i -o test.s # -S 表示从现在开始,执行程序的翻译,做完编译工作之后,变成汇编代码就停下来 # 变成的汇编代码的后缀名是.s
打开test.s之后我们可以发现,里面的代码意见已经变成汇编指令了。
3.汇编
此阶段做的事情:把汇编代码变成二进制(这里的二进制不是可执行的,叫做二进制目标文件)
在Linux下需要执行的指令是:
gcc -c test.s -o test.o # -c 表示从现在开始,进行程序的翻译,做完汇编工作,变成可重定向的目标二进制,就停下来 # 重定向的目标二进制文件的后缀名是.o
可以看到,此时文件内已经变成了我们看不懂的二进制代码,当他以二进制的形式打开时,是这样的
4. 链接
此阶段做的事情:把本地编写的代码和c标准库中的代码合并,形成可执行的二进制文件
- 合并段表:编译器会把在汇编阶段生成的多个目标文件中相同格式的数据合并在一起,最终形成一个 .exe 文件。
- 符号表的合并和重定位:符号表的合并是指编译器会把在汇编阶段生成的多个符号表合并为一个符号表;重定位则是指当同一个符号出现在两个符号表中时,编译器会选取其中和有效地址相关的那一个,舍弃另外一个
在Linux下需要执行的指令是:
gcc test.o -o mytest # 链接阶段是程序翻译的最后一个阶段,不需要加任何选项 # 默认生成的可执行文件的文件名是a.out,我们可以通过-o选项指定
可以看到,产生的文件mytest就是可执行的程序。
注:
- 对于上述的几个Linux下gcc指令的选项和产生文件的后缀名,这里有一个方便记忆的小技巧,预编译、编译、链接的选项分别是ESc,对应着键盘左上角的按键Esc,产生的文件后缀名是iso,对应着光盘映像文件的后缀名
- 上述的分段执行只是为了方便我们能够更加细致的看到程序翻译的过程,在实际使用gcc的时候,只需要使用指令gcc 原文件名 -o 产生的可执行文件名或者gcc 原文件名即可。