一、被隐藏的过程
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
在Linux下,当我们使用GCC来编译Hello World程序时,只需使用最简单的命令(假设源代码文件名为hello.c):
gcc hello.c // 生成a.exe文件
a.exe
输出:
Hello World
事实上,上述过程可以分解成4个步骤,分别是预处理、编译、汇编和链接。 如下图。
1.1 预编译
在预编译阶段,源文件和头文件会被处理成.i为后缀的文件。
对hello.c文件预编译成.i文件,命令如下( -E表示只进行与编译 ):
gcc -E hello.c -o hello.i
预编译过程主要处理那些源代码中以“#”开始的预编译指令。比如“#include”、“#define”等,主要处理规则如下:
- 将所有的“#define”删除,并且展开所有的宏定义。
- 处理所有条件编译指令,比如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”。
- 处理“#include”预编译指令,被包含的文件插入到该预编译指令的位置。注意:这个过程是递归进行的,也就是说被包含的文件还可以1包含其他文件。
- 删除所有的注释。
- 添加行号和文件名标识,比如 # 1 "hello.c" ,以便于编译时产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
- 保留所有的 #pragma 编译器指令,因为编译器需要使用它们。
结果预编译后.i文件不包含任何宏定义,因为所以的宏定义已经被展开,并且包含的文件也已经被插入到.i文件中。所以当我们无法判断定义是否正确或头文件是否正确,可以查看预编译后的文件来确定问题。
1.2 编译
编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件。
把hello.i编译成hello.s文件,命令如下:
gcc -S hello.i -o
1.3 汇编
汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。
命令如下:
gcc -c hello.s -o hello.o
使用gcc命令从C源代码文件开始,结果预编译、编译和汇编直接输出目标文件:
gcc -c hello.c -o hello.o