通常,我们在像VC或VS这样的IDE集成开发平台写好一个程序之后,点击两个按钮,一个编译按钮,一个运行按钮。如果程序没有错误,那么我们将会看到预想的结果,并生成一个*.exe的可执行程序。
在linux系统下,常用vim编辑器来编写程序,写好程序以后,需要gcc编译器来对程序进行编译和链接。通常会生成一个*.out的可执行文件。
然而,事实上,以上过程可以分为4个步骤,分别是预处理(Prepressing),编译(Compilation),汇编(Assembly)和链接(Linking),如下图
了解程序的编译过程,不仅可以使我们更深刻的理解程序是如何从文本到二进制的可执行程序。而且在编译出错时候,使我们更容易调试和优化程序。这对程序员来说是至关重要的。
因为集成开发平台中间过程的封装性,我们无法查看中间过程和中间文件。所以我们选择用gcc编译器来产生中间文件并做分析。
首先用vim编辑器编写C程序源文件 hello.c
源文件 2 hello.c(为了更清晰的表现预处理过程对条件预编译指令的处理方法)
1,预处理(Prepressing)
在gcc编译器环境下,我们可以通过改变gcc命令的参数选项来控制gcc的执行。如下:
gcc [选项] [文件] |
- E:只预处理,生成*.i的文件,不进行编译,汇编和链接 |
-S:只进行编译,生成*.s的文件,不进行汇编和链接 |
-c:只进行汇编,生成*.o的文件,不进行链接 |
-o 文件:输出到文件 |
-g:加入调试信息,可以用gdb调试器调试程序 |
输入gcc命令:gcc hello.c -E> hello.i 并查看hello.i内容,如下图:
源文件1的预处理结果,如下图:
总结:可以发现在预处理阶段,预处理器做了以下工作:
(1)将头文件”#include<stdio.h>“的实际内容替换到"头文件包含位置"。
(2)删除所有的注释”//“和”/* */“。
(3)将”#define“删除,并且展开所有的宏定义。
(4)添加行号和文件名标识
(5)处理所有条件预处理指令,比如”#if“, "#ifdef", "#elif", "#else", "#endif".(下图是源代码2的预处理后的结果)。
2 编译
编译后生成hello.s文件,用vim hello.s查看一下,文件内容。
总结:编译器的工作就是把预处理文件hello.i进行一系列的词法分析,语法分析,语义分析及优化后生成相对应的汇编代码文件hello.s。
3 汇编
总结:汇编器是将汇编代码文件hello.s变为机器可以执行的指令。(此时已经是二进制文件,但是还不能够被执行,因为还未加入启动代码陈旭和链接库函数等)。
4 链接
总结:链接器将经过汇编器生成的二进制代码文件hello.o和库函数的*.o文件还有其它源文件的*.o文件(本文示例文件为一个源文件)进行链接,最后载入启动代码。那么这个程序就可以在linux环境下运行了,我们可以看到,最终输出了37.680000半径为2的圆的周长。
本文知识简要的介绍了编译的过程,如有对编译和执行过程有强烈的兴趣那么《程序员的自我修养》这本书就是为您准备的!