编译器的工做过程

简单的说,其实要理解cpp文件与头文件有什么不一样之处,首先须要弄明白编译器的工做过程,通常说来编译器会作如下几个过程:函数

1.预处理阶段(也就是常说的切token)spa

2.词法与语法分析阶段code

3.编译阶段首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件 (.obj文件)blog

4.链接阶段将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,固然,最后还能够用objcopy生成纯二进制码,也就是去掉了文件格式信息。(生成.exe文件)token

编译器在编译时是以cpp文件为单位进行的也就是说若是你的项目中一个cpp文件都没有,那么你的项目将没法编译。链接器是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位(肯定每一个函数和变量相对于程序起始位置的地址,这里还不是真正的内存的地址,真正内存的地址要等到程序载入器根据某个寄存器的地址肯定),生成最终的可执行文件。在PC上的程序开发,通常都有一个main函数,这是各个编译器的约定。固然,你若是本身写链接器脚本的话,能够不用main函数做为程序入口!!!!内存

  (main .c文件  目标文件  可执行文件)开发

有了这些基础知识,再言归正传,为了生成一个最终的可执行文件,就须要一些目标文件,也就是须要cpp文件,而这些cpp文件中又须要一个main函数做为可执行程序的入口,那么咱们就从一个cpp文件入手,假定这个cpp文件内容以下:编译器

main.c函数io

#include <stdio.h> #include "mytest.h"

int main(int argc,char **argv) { test = 25; printf("test.................%d\n",test); return 0; }

mytest.h头文件内容以下:编译

int test;

如今以这个例子来说解编译器的工做:

1.预处理阶段:编译器以cpp文件做为一个单元,首先读这个cpp文件,发现第一句与第二句包含一个头文件,就会在全部搜索路径中寻找这两个头文件,找到以后,就会到相应头文件中再去处理宏、变量、函数声明、嵌套的头文件等,检测依赖关系,进行宏替换,看是否有重复定义与声明的状况发生,最后将那些文件中全部的东东所有扫描进这个当前的cpp文件中,造成一个中间"cpp文件"。

在这一步中至关于将那个头文件中的test变量扫描进了一个中间cpp文件,那么test变量就变成了这个文件中的一个全局变量。在stdio.h这个头文件中有一些函数的声明,这时也把这些函数的声明一股脑的扫描到了这个中间cpp文件中(只是扫描了函数的声明,并无实现)。

2.编译阶段:此时就为这个中间cpp文件的全部变量、函数形参分配空间(原则上,在这里只能看到.h文件中函数、变量的声明,为变量和函数的形参等分配空间),将各个函数编译成二进制码,按照特定目标文件格式生成目标文件,在这种格式的目标文件中进行各个全局变量、函数的符号描述(编译器维护一个符号描述表),将这些二进制码按照必定的标准组织成一个目标文件。

此时的每个cpp文件都被编译器编译成了一个目标文件,同时每一个目标文件都有一张符号表,这张符号表中记录了这个cpp文件都用到了哪些变量,哪些函数,函数的参数是什么类型的,有几个参数。同时为变量和函数形参开辟了内存空间。因此这里编译器把你这个cpp用到的全部的东西都记录下来了,若是有重复定义或者没有定义的变量、函数等,编译器一会儿就知道了。

3.链接阶段:将上一步成生的各个目标文件,根据一些参数,链接生成最终的可执行文件,主要的工做就是重定位各个目标文件的函数、变量等,至关于将个目标文件中的二进制码按必定的规范合到一个文件中。

相关文章
相关标签/搜索