认识 C 的编译器和编译流程
GCC 的编译流程
我们写的 C 代码保存在扩展名是 .c 的文件,其实是一个纯文本文件。
- GCC(C 编译器之一)通过预处理器(Pre-Processing)把头文件展开到
hello.i
文件中。 - 编译器(Compiling)把
hello.i
文件转换成包含汇编代码的文件hello.s
中。 - 汇编器(Assembling)把
hello.s
文件转换成二进制文件——目标文件hello.o
。 - 链接器(Linking)把库文件编译成 xx.o 文件,并与启动代码结合起来,最终生成一个可执行文件。
GCC 的编译步骤
第一阶段
把 hello.c(源文件)转换成 hello.i,gcc -E hello.c -o hello.i
。
第 419 行的函数非常熟悉,在 IDE 中显示的代码也是这样。而这些代码都是来自于#include <stdio.h>
头文件里的,也就是库文件。
.i 文件的内容与 .c 文件的内容有很大的不同。.c 文件中使用的 printf() 函数在源代码中好像是未定义,其实在 .i 文件中是把<stdio.h>
的代码复制粘贴到了 .i 文件中。
第二阶段
把 hello.i 转换成 hello.s(汇编文件),gcc -S hello.i -o hello.s
。
.s 文件还是一个文本文件,打开该文件查看,到这里就已经把源代码文件转换成了包含汇编指令的文件。
第三阶段
把 hello.s 转换成 hello.o,gcc -C hello.s -o hello.o
。
.o 文件是一个目标文件,里面都是一堆二进制代码,但目前还不能被执行。打开这个文件一看,一堆红色的二进制,还有些许乱码。
第四阶段
生成可执行文件,gcc hello.o -o hello
。
这里出现了一个错误,但从中得知,这一阶段链接器正在发挥它的作用:要把你编写的目标代码、系统的标准启动代码和库文件代码三个部分合并成一个文件,即可执行文件。