编译过程分为4段:
- 预处理
- 编译
- 汇编
- 链接
注:现在版本的GCC把预处理和编译两个步骤合成一个步骤,用cc1工具来完成。gcc其实是后台程序的一些包装,根据不同参数去调用其他的实际处理程序,比如:预编译编译程序cc1、汇编器as、连接器ld
1. 预处理
.c —>.i
预处理的过程主要处理包括以下过程:
- 将所有的#define删除,并且展开所有的宏定义
- 处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif等
- 处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
- 删除所有注释 “//”和”/* */”.
- 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
- 保留所有的#pragma编译器指令,因为编译器需要使用它们
命令实现:
#用gcc的-E命令实现,参数-E表示只进行预处理
gcc -E *.c > *.i
#或者也可以使用以下指令完成预处理过程
cpp hello.c > hello.i
直接cat hello.i 你就可以看到预处理后的代码
2. 编译
.i —> .s
编译过程就是把预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。
命令实现:
#用gcc的-S(大写)命令实现
gcc -S *.i > *.s
3. 汇编
.s —> .o
汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
命令实现:
#用gcc的-c只编译不链接
gcc -c *.s > *.o
#或者
as hello.s –o hello.co
由于hello.o的内容为机器码,不能以普通文本形式的查看(vi 打开看到的是乱码)。
4. 链接
*.o —>[filename]
通过调用链接器ld来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件。
命令实现:
gcc -o hello hello.c
链接分为静态链接和动态链接
- 静态链接
指编译连接时,把库文件的代码全部加入到可执行文件中去,因此生成的文件比较大,但在运行时也就不需要库文件了。
- 动态链接
是指在编译时不把库文件加载到可执行文件中去,而是在程序执行时由运行时链接文件加载库。动态链接可节省系统开销。