C语言:程序中的预处理、编译、汇编和链接过程

索引:鼠标右键上拉可回来

    • 1、写在前面的话
    • 2、预处理阶段(cpp)
    • 3、编译阶段(cc)
    • 4、汇编阶段(as)
    • 5、链接阶段(ld)
    • 6、补充


1、写在前面的话

这篇博客主要记录下C语言程序从源文件变成可执行程序的过程,在Linux系统中,GCC执行这个过程分为四个阶段:预处理、编译、汇编和链接,整个过程是通过编译工具链实现的。
C语言:程序中的预处理、编译、汇编和链接过程_第1张图片


2、预处理阶段(cpp)

命令 gcc -E main.c -o hello.i

说明:进行预处理操作时,预处理器会对以#开头的预处理命令进行处理。比如:#include ,预处理器会将系统中的stdio.h的具体内容读取到文本中,替换原有的#include ,得到一个新的C文件,也就是i文件。

备注:之后还会详细记录下预处理中的一些事情。


3、编译阶段(cc)

命令 gcc -S main.i -o hello.s
或者 gcc -S main.c -o hello.s

说明:第一种方式是由编译器单独完成的,第二种是由预处理器和编译器一起完成的,编译器将main.i翻译成了main.s汇编文件,汇编程序是一条条通用的机器语言指令。

备注:编译时,编译器需要检查语法、函数与变量声明的正确,语法的正确是对于每个文件中基本指令的准确性,函数与变量的声明则需要告诉编译器头文件所在的位置。(声明在头文件,定义在C/C++文件),所有的语法正确,编译器就可以编译出中间目标文件。


4、汇编阶段(as)

命令 gcc -c main.s -o main.o

说明:汇编器会将main.s翻译成机器指令,将这些机器指令打包成*.o格式的可重定位文件,并将结果保存在目标文件中。目标文件是由不同的段组成的,通常一个目标文件至少有两个段–数据段和代码段,main.o用文本文件打开之后是看不懂的,因为是二进制文件。


5、链接阶段(ld)

命令 gcc main.o -o main.out

说明:链接是最后一个过程,链接器会将main.o和其他库文件、目标代码文件链接后形成可执行程序(把大量的ObjectFile合成执行文件),比如:假设main.c中调用了函数printf,链接器会将printf.o文件并入我们的main.out可执行文件中,最后将可执行文件加载到存储器中,然后由系统执行。

备注:一般每个源文件,应该都有对应于一个中间目标文件(.o或.obj文件)。


6、补充

01 平时我们说的编译器实质上指的是编译工具链,由于习惯的原因,平时我们经常只说了编译链接,这里的编译不是第二阶段,而是包含了预处理、编译和汇编的三个过程,也就是由源程序文件生成中间代码文件的过程(有点坑,习惯的东西之前一直没理清楚)。而且,实际上,预处理用预处理器,编译用编译器,汇编用汇编器,链接用链接器,这几个工具再加上一些其他额外会用到的工具,合起来就叫做编译工具链,平时经常用到GCC就是一个编译工具链。

02 为了适应习惯吧,我以后也会叫这整个过程为编译链接。但要明白里面这些东西(其实好比CPU和SoC),要不然别人说起预处理,我第一次的反应一直不知道是在哪里。

03 编译链接中各种文件扩展名

扩展名 含义
.c文件 C语言源代码文件
.a文件 由目标文件构成的静态文件
.c文件 C++源代码文件
.h文件 程序所包含的头文件
.i文件 预处理的C源代码文件
.ii文件 预处理的C++源代码文件
.m文件 Objective-C源代码文件
.o文件 编译后的目标文件
.out文件 链接器生成的可执行文件
.s文件 汇编语言源代码文件,后期不再进行预处理操作
.S文件 汇编语言源代码文件,后期还会进行预处理操作,可以包含预处理指令

04 Windows的中间代码文件是.obj,Unix/Linux的中间代码文件是.o。

05 链接时,主要是链接函数和全局变量,可以使用这些中间目标文件来链接我们的应用程序,整个链接过程不需要理会源文件,只需关注中间目标文件,大多数情况下,由于源文件太多,编译生成的中间目标文件太多,而且在链接的时候,需要明确地指出中间目标文件名,这对编译十分不方便。所以,我们要给中间目标文件打个包,在Windows下这种包叫做“库函数”(library file),也就是.lib文件,在Unix\Linux下,是Archive File静态库文件,也就是.a文件。

06 小结:源文件生成可执行程序的过程中,源文件首先会生成中间目标文件,再由目标文件生成执行文件。在编译的时候,只检测语法、函数与变量声明是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成目标文件,在链接程序时,链接器会在所有的目标文件中找寻函数的实现,如果找不到,那就会再报链接错误码(Linker Error)。


你可能感兴趣的:(C语言)