当我们写好了一份可执行的代码,并且满怀期待的按下执行按钮,屏幕上输出了想要的结果,这时有没有好奇过,计算机是如何做到这一切?
通过学习,可以了解到整个过程分为四个步骤:
一、预编译
在这个初级处理阶段,源代码以及相关的头文件被预编译成为一个.i文件,主要有:
- 展开所有的宏,并删除“#define”,引入头文件”#include”
- 删除注释,处理条件预编译指令,保留#pragma编译指令
- 添加行号和文件名标识,用于编译时产生调试用的行号以及报错时显示行号
需要注意的是,在这一阶段并无语法、语义的检测,并不能查错
二、编译
紧接着上一阶段,将.i文件进行语法、语义的分析,生成汇编代码文件.s,主要有:
1.词法分析:
扫描器读取源代码,将源代码的字符序列分割成为一系列的记号,有关键字、标识符、数字、字符串,以及特殊的加号、等号等运算符。在分割的同时,扫描器将标识符放到符号表,将数字、字符串常量放到文字表等。
2.语法分析:
由语法分析器对扫描器产生的记号进行语法分析,产生语法树——以表达式为节点的树 ,符号和数字是最小的表达式,所以通常作为叶节点。
在语法分析的同时,运算符号的优先级、含义被确定,多重含义加以区分,对不合法的表达式进行语法分析阶段的错误报告。
3.语义分析:
只能对静态语义进行分析,即在编译期间可以确定的语义,并且是语法层面的分析,并不明确语句的真正意义,只是完成声明和类型的匹配,类型的转换。经过语义分析后,整个语法表达树都被标记了类型,如果有类型需要做隐式转换,语义分析程序会在语法树中插入相应的节点。
4.生成中间语言:
编译器会在源码级别进行一些优化,对于值可以确定的表达式,将被优化为对应的值。中间代码主要有三地址码和P-代码。
三、汇编
将中间代码转换为目标机器代码,并进行一些优化。每一个汇编语句几乎都对应一条机器指令,汇编过程就是根据汇编指令和机器指令的对照表一一翻译。这个过程十分依赖目标机器,不同机器有着不同的字长、寄存器、整型数据类型和浮点数据类型。
四、链接
经过预处理、编译、汇编,源代码终于成为了目标文件,但是目标文件中可能有变量定义在其他模块,这些定义在其他模块的全局变量和函数在最终运行时的绝对地址都要在最终链接时确定,所以编译器将一个源代码文件编译为一个未连接的目标文件,然后由链接器最终将这些目标文件链接起来形成可执行文件。
链接的过程包括地址和空间分配、符号决议(符号绑定、名称绑定、名称决议)和重定位。
具体的过程将在后续的博客中详解。
参考书籍《程序员的自我修养》—链接、装载与库