对于每一门语言来说。“Hello World”程序几乎是一个开始,每个程序员闭着眼睛都能写得出来。
#include<stdio.h>
int main()
{
printf("Hello World!");
return 0;
}
在Linux下,当我们使用GCC来编译Hello World程序时,只需要使用最简单的命令(假设源代码文件名为hello.c):
#gcc hello.c
#./a.out
hello world
事实上,对于上述过程可以分为四个过程,预处理(Prepressing)、编译(Compliation)、汇编(Assembly)和链接(Linking)。
1.预编译 (Prepressing)
经过预编译的结果:hello.c ------> hello.i
即首先将源代码文件hello.c和相关的头文件,如stdio.h等预编译器cpp预编译成为一个.i文件。而与编译过程主要处理那些源代码中的以“#”开始的预编译指令,主要任务如下:
- 将所有的“#define”删除,并且展开所有的宏定义。
- 处理所有条件预编译指令,比如“#if”,“#ifdef”,“#elif”,“#else”,“endif”。
- 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
- 删除所有的注释“//”和“/*”。
- 添加行号和文件名标识,比如#2“hello.c”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
- 保留所有的#pragma编译器指令,因为编译器须要使用它们。
2.编译 (Compliation)
经过编译的结果:hello.i ------> hello.s
编译过程就是把与处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件,这个过程往往是我们所说的整个程序构建的核心部分。
3.汇编(Assembly)
经过汇编的结果:hello.s ------> hello.o
汇编器是将汇编代码转变为机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,不需要复杂的语法、语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了。
4.链接(Linking)
经过链接的结果:hello.o ------> a.out
链接的主要内容就是将各个模块之间相互引用的部分都处理好,是的各个模块之间能够正确的衔接。最终将一大堆文件链接起来得到”a.out“,即最终的可执行文件。