目录
翻译环境可以将源代码转化为可执行的机械指令,翻译环境包括编译和链接两大部分。
编译又可以分为:预处理(预编译),编译,汇编三大过程。
下面是翻译环境大致过程:
分析:
1.多个.c文件单独经过编译器编译生成后缀为.obj的目标文件,这个过程为编译
(在Windows环境下的目标文件后缀为.obj ,Linux环境下的为.o)
2.多个目标文件和链接库一起通过链接器链接最终生成可执行程序。
3.链接库:支持程序运行的的基本函数集合。
以gcc为列把编译详细拆解:如图所示
如上图可以看到在编译过程中预处理后的文件带有 .i 后缀,做出的处理如下
将所有#define删除,并且展开所有宏定义。
处理所有条件编译指令:如#if ,#ifdef,#elif,#endif
处理#include预编译指令,将所有包含的头文件的内容插入到预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。
删除所有注释
添加行号和文件名,方便后续编译器生成调试信息等。
保留所有#pragma的编译指令,编译器后续使用
注意:经预处理后的.i文件中不再包含宏定义,宏已经被展开。并且包含的头文件都被插入到.i文件
中。因此当我们无法知道宏定义或者头文件是否被包含正确的时候,可以查看预处理后的.i文件确认。
编译就是将预处理后的文件进行:词法分析,语法分析,语义分析。之后生成相应的汇编代码文件。
词法分析:
语法分析:
语义分析
汇编是将由编译生成的汇编代码转化成机器可执行的指令,每一个汇编语句对应一条机器指令。
根据汇编指令和机器指令的一一对照表进行翻译,不做任何指令优化。
链接是把一堆文件链接在一起生成可执行程序。
过程包括:地址和空间的分配,符号决议和重定位等问题。
链接解决了一个项目中多文件多模块相互调用的问题
test.c经过编译器处理生成test.obj
add.c经编译器处理生成add.obj
在test.c中引用了add.c中的add函数和a_c变量。
在test.c中每次使用add和a_c都需知道其地址,但由于每个文件是单独编译的,编译器在编译add和a_c时不知道其地址,先将调用的add和a_c地址搁置。等到最后链接时,由链接器引用到的add符号在其它模块中查找add的地址,然后将test.c中引用到add的指令修改,使其目标地址为真正add函数地址。对于a_c也是如此。这个地址修订过程叫重定位。
1.程序的运行需要载入内存,在有操作系统的的环境中,这个由操作系统完成。在独立的环境中程序的载入由手动安排。
2.程序一旦执行便开始寻找main函数
3.开始执行程序代码,程序会使用运行时的堆栈,储存函数的局部变量和返回地址。
4.终止程序,正常终止也可能意外终止。