从程序源代码到可执行文件经历了什么?

编译预处理、编译、汇编、链接

编译预处理

对于C++程序来说,他的源代码文件的扩展名可能是.cpp或.cxx,头文件的扩展名可能是.h或.hpp,预编译后的文件扩展名是.ii.

第一步预编译的过程相当于如下命令:

1
2
3
gcc -E test.c -o test.i
或者
cpp test.c > test.i

预编译过程主要处理那些源代码文件中的以”#“开始的预编译指令,例如”#include“、”#define“等

主要的处理规则如下:

  • 将所有的“#define”删除,并且展开所有的宏定义。

  • 处理所有的条件编译指令

  • 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件中还可能包含其他文件。

  • 删除所有的注释

  • 添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。

  • 保留所有的#pragma编译器指令,因为编译器须要使用他们。

经过预编译后的文件不包含任何宏定义。

编译

编译过程就是把预处理后的文件进行一系列的词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件。

1
gcc -S test.i -o test.s

汇编

汇编器是将汇编代码转变成机器可以执行的指令,每一条汇编语句几乎对应一条机器指令。

1
gcc -c test.s -o test.o

链接

程序的模块化是人们一直在追求的目标,当一个系统十分复杂的时候,我们需要将一个复杂的系统逐步分割成小的系统以达到各个突破的目的,程序员将每个源代码模块独立的编译,按照需要将他们”组装”起来,这个组装模块的过程就是链接。

链接的主要内容就是将各个模块之间相互作用的部分都处理好,使得各个模块之间能够正确的衔接。从原理上来讲,链接器所做的工作就是把一些指令对其他符号地址的引用加以修正。

关于链接请看另一篇文章

汇编?链接?