一:程序执行过程:
1. .c/.cpp+.h文件
预编译:
(1)将所有的”#define”删除,并展开所有的宏定义
(2)处理所有条件预编译指令,比如”#if” “#endif” “elif” “else” “#endif”
(3)处理“#include“预编译指令,将被包含的文件插入到该预编译指令的位置
(4)删除所有的注释
(5)添加行号和文件标识名,以便于编译时编译器产生调试用的行号信息以及用于编译时产生编译错误或者警告时能够显示行号
(6)保留所有的#pragma编译器指令,因为编译器必须要使用他们
在预编译后的.i文件不含有任何的宏因为所有的宏已经被展开,包含的头文件也已经插入到.i文件中。所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定
2. .i文件
编译:修改之后的源代码变为汇编代码 3.5.6章
顺序:
- 扫描、词法分析
- 语法分析: 产生语法树
- 语义分析:语法正确的不一定有真正意义 比如两个指针乘法运算语法正确但是无意义
语义分析有:
- 编译器所能分析的语义是静态语义,即编译期可以确定的语义
静态语义通常包含声明和类型匹配、类型转换等
- 与之对应的就还有动态语义只有在运行期才能确定的语义
- 源代码优化:源代码优化在语法树上优化比较困难,所以将语法树转化为中间代码 中间代码将编译分为前后端,之前都是编译器前端 之后都是编译器后端
- 代码生成
- 目标代码优化
3. .s文件
汇编:将汇编代码转变为机器可以执行的二进制指令
将汇编程序变为可重定位目标程序(二进制)
4. .o文件(目标文件 可重定位目标文件 经过符号解析、符号重定位)
链接:将目标文件通过经过合并段和符号表、符号解析、符号重定位、更改ELF头地址 变为可执行目标文件(包括使用到的库函数中的各种.o文件的链接)
5.可执行文件(windows下是.exe Linux下是ELF)