C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。过程图解如下
从上图可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的大括号括起的部分,其余则为链接过程。
编译过程
编译过程又可以分成两个阶段:编译和汇编。
编译
编译过程包含两个主要阶段:
第一个阶段是预处理阶段,主要是以下几方面的处理:
(1)宏定义指令,如 #define a b
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
(3) 头文件包含指令,如#include "FileName"或者#include <FileName>等。
预处理之后得到的仍然是文本文件,但文件体积会大很多。
第二个阶段编译。
编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
预处理之后得到的仍然是文本文件。
汇编
汇编实际上指把汇编语言代码翻译成目标机器指令的过程。
对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。
汇编之后的文件是二进制文件。
链接
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体
链接处理可分为两种:
(1)静态链接。在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
(2) 动态链接。在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
我们在linux使用的gcc编译器便是把以上的几个过程进行捆绑,使用户只使用一次命令就把编译工作完成,这的确方便了编译工作,但对于初学者了解编译过程就很不利了,下图便是gcc代理的编译过程:
预处理指令:gcc -E -I./inc test.c -o test.i
编译指令: gcc -S -I./inc test.c -o test.s
汇编指令:gcc -c test.s -o test.o
链接指令:gcc