C语言编译过程主要由四个步骤组成:预处理、编译、汇编、链接,最后得到一个可执行程序,在Unix/Linux平台上一般显示后缀为.out,在Windows上显示后缀为.exe,那在生成可执行文件的过程中编译器到底做了什么呢?一个.c文件是怎么一步步变成可执行文件?
-
预处理
-
包含的头文件替换成对应的函数声明
-
宏定义的展开,进行字符串的替换
-
处理条件编译指令,如#ifdef/#else/#ifndef/#endif等
-
删除代码中的注释
-
文件添加行号和标识
新建test.c,添加以下内容
由图1可看出.c生成.i文件大小有17k,那为什么生成的.i文件比原文件大这么多?
图1
我们可以粗略看下.i文件里的内容,如图2,几乎都是一些函数声明,宏定义被替换成对应字符串
图2
-
编译
编译实质就是将高级语言转换成汇编语言,由.i 文件到.s文件的过程。具体主要做了以下一些事:
-
语法分析,检测程序中是否存在语法错误就是在这个阶段进行的
-
将源码翻译成汇编代码
-
对代码进行优化
gcc -S test.i -o test.s 生成对应汇编代码,具体内容图3
图3
-
汇编
汇编的过程是把生成的汇编代码转换成机器码,即.s 到 .o的过程。
gcc -c test.s -o test.o 生成test.o文件,Windows下对应.obj文件,其中的内容是人看不懂的,只能看到一些系统内存空间的分布信息
图4
-
链接
在链接之前的.o文件还不能直接运行,需要将二进制文件所用到的外部库绑定才能正常运行
gcc -c test.o -o test 由.o最终生成可执行文件,查看test.o 和 test 的文件属性,如图5所示,可看出test是一个可执行的文件,动态链接了一些库文件,而test.o是一个可重定位的文件(包含了代码与数据,可以用来链接成可执行文件或共享目标文件,如目标文件与静态链接库)
图5
链接分为静态链接和动态链接:
-
静态链接:在编译阶段把使用到的库链接到可执行文件,生成的文件较大,但执行速度快,不需要寻找链接库内容
-
动态链接:在链接阶段只是添加一些使用库的描述信息,在程序运行时,再从系统把相应的动态库加载到内存,可执行文件小,但执行速度相对静态链接较慢,要在内存查找链接库内容
如有错误,欢迎指出!