0. 流程概览
- 编译流程:预处理 → 编译 → 汇编 → 链接
- 详细
- → 源代码(source code).c / .cpp
- 预处理器(processor)→ ?
- 编译器(compiler)→ 汇编代码(assembly code).s
- 汇编器 (assembler)→ 目标程序(object code).o /.obj
- 链接器(linker) → 可执行程序(executables)/ .exe
1. 预处理
经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件;
仅仅是文件内容上的变化;
- 读取C/C++源程序,对其中的伪指令(以#开头的指令)进行处理
- 解决宏定义:删除 #define ,展开所有宏定义
- 处理条件编译指令:如 #if #ifdef #elit #else #endif 等,会过滤掉不必要的代码
- 处理#include预编译指令,将被包含的文件插入到预编译指令的位置(递归进行,因为被#include的文件可能还#include了其他文件)
- 删除所有注释:// /**/
- 添加行号和文件名标识:便于调试
- 保留所有的 #pragma 编译器指令
2. 编译
- 词法分析、语法分析、语义分析、优化(分为针对代码的优化和针对计算机的优化)
- 产生汇编代码;
- 针对一个编译单元:一个.cpp文件以及其中 #include 的 .h 文件
3. 汇编
- 将编译完的汇编代码文件翻译成机器指令(2进制),并生成可重定位目标程序的.o文件
- 基本一条汇编语句对应一条机器指令。(对应的是虚拟地址)
- 目标程序:
- .o / .obj文件:每个cpp文件都会被编译成一个.o文件
4. 链接
- 通过链接器将一个个目标文件(或许还有库文件)链接在一起生成一个完整的可执行程序。
- 将 .obj 文件与库文件 .lib 等链接,生成可执行文件 .exe,使得这些目标文件称为一个能够被OS装入执行的统一整体。
- 比如:某个源文件中的函数引用了另一个源文件中定义的某个符号(变量或者函数调用等);或者是调用了某个库文件中的函数等等。
- .cpp文件以分离的方式经过编译汇编以后,再进行链接。(否则该 .o 文件总不一定有main函数)
参考资料: