被隐藏的构建过程
编译和链接
集成开发环境(IDE)一般将编译和链接的过程一步完成,这个过程叫做构建(Bulid),也有人翻译成生成.
构建的过程:
预处理(Prepressing)→编译(Compilation)→汇编(Assembly)→链接(Linking)
预编译
预编译过程主要处理那些源代码文件中的以#开始的预编译指令.主要处理规则如下
1.删除#define,展开所有宏定义
2.处理所有条件预编译指令
3.处理#include,将被包含的文件插入到该预编译指令的位置(递归进行)
4.删除所有注释
5.添加行号和文件名标识,便于编译时错误\警告\调试信息显示行号
6.保留所有#pragma指令
编译
词法分析:扫描器(Scanner)运用一种类似于有限状态机(Finite State Machine)的算法将源代码分割成一系列的记号(Token)
记号可以分为以下几类:关键字\标识符\字面量\特殊符号.
语法分析:语法分析器(Grammar Parser)采用上下文无关语法(Context-free Grammar)的分析手段产生语法树(Syntax Tree)
语法树:一种以表达式(Expression)为节点的树
语义分析:语义分析器(Semantic Analyser)能分析静态语义(Static Semantic)和动态语义(Dynamic Semantic)
静态语义是在编译器可以确定的语义,通常包括声明和类型的匹配,类型的转换.
动态语义是只由在运行期才能确定的语义.
中间语言生成:源码级优化器(Source Code Optimizer)将整个语法树转换成中间代码(Intermediate Code)
它是语法树的顺序表示,已经非常接近目标代码了,但它一般跟目标机器和运行时环境是无关的.
中间代码由很多类型,不同编译器有着不同的形式,比较常见的有三地址码(Three-address Code)和P代码(P-Code)
目标代码生成与优化:代码生成器(Code Generator)将中间代码转换成目标机器代码,这个过程十分依赖于目标机器,因为不同的机器有着不同的字长\寄存器\整数数据类型和浮点数数据类型等
目标代码优化器对目标代码进行优化,比如选择合适的寻址方式\使用移位来代替乘法运算\删除多余的指令等
对于不同的编程语言,编译器开发者只需改变词法和语法规则
不同编译器的源码级优化器可能有不同的定义或有一些其他的差异
高级编程语言的复杂导致编译器结构复杂
计算机CPU的复杂导致编译器的机器指令优化过程复杂
支持多种硬件平台导致编译器的指令生成过程复杂
汇编
汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令.只需要根绝汇编指令和机器指令的对照表一一翻译即可.
链接
主要解决模块之间如何通信的问题
最常见的属于静态语言的C/C++模块之间通信有两种方式:模块间的函数调用和模块间的变量访问。
都可以归结为一种方式:模块间符号的引用
链接过程主要包括:地址和空间分配(Address and Storage Allocation)、符号决议(Symbol Resolution)、重定位(Relocation)