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