首先简单介绍一下编译链接这个过程,顾名思义,编译链接是编译和链接两个过程组成的,其中,编译又可以细分为预编译、编译和汇编。这两个步骤让我们编写的.cpp文件能够让电脑看懂,变成一个可执行文件。
下面我将展开讲一下他们都做了什么。
编译过程
预编译:
也叫做预处理,是编译阶段的第一步。再这个过程,会对程序做一些简单的处理
1.删除#define,并展开宏定义
2.处理条件预编译指令,如#if、#endif、#elif、#else
3.处理#include预编译指令,并把包含的头文件都插入到代码中去。
4.删除所有的注释
5.添加行号和文件名标识
6.值得注意的是,要保留#pragma编译器指令,这个要留到链接阶段,用来告诉编译器程序需要链接的库
预编译会把.c文件和与之对应的.h头文件编译到一起,生成一个.i文件。(要注意,多个.c文件是分开编译的)
编译:
最复杂的一个阶段,再这个过程中,会把预编译完的文件(.i文件)变成一个汇编文件(.s文件)
包含的过程有:词法分析、语法分析、语义分析、源代码的优化。
简单说明一下,词法分析就是把单词都加上标记,比如 a = 2+3,会表示为这样:
记号 | 类型 |
a | 标识符 |
= | 赋值 |
2 | 数字 |
+ | 加号 |
3 | 数字 |
然后是语法分析,就是把前面的记号连起来,生成一棵语法树:
接着是语义分析,在这一步会检查语句的正确性,比如0被用做了除数,会在这一步报错,同时会把类型加上,写入语法树中(不画了,就是每个框里都会多一个它的类型)。
最后是源代码的优化,比如我们这里的2+3,会直接运算得到5,然后把结果重新放回语法树中。(其实没有这么简单,有兴趣的自己可以去了解下)
汇编:
编译的最后一步,把汇编文件一行一行解读,然后翻译成一个二进制可重定位目标文件 (.o文件)。
到这里,电脑已经可以看懂我们的程序了,但还不能真正去运行它,我们还需要做另一步,也就是链接。
链接过程
简单来说,链接就是把刚刚所有的目标文件.o文件全都链接起来,生成一个可执行文件
它包含了几个较重要的步骤,符号决议(符号绑定)、地址和空间分配、重定位、生成可执行文件。
简单讲就是先找到符号的定义,然后分配一个虚拟地址,然后更新这个虚拟地址到文件中。
详细过程可以去看《程序员的自我修养》,本文大多也是对这本书部分内容的总结和理解。