一个hello world的编译原理


一个简单的hello world 程序
#include <stdio.h>

int mian ()
{
    printf("Hello World\n");
    return 0;
}
通过$gcc hlello.c $./a.out 可生产Hello World
事实上,上述过程可以分解为4个步骤,分别是预处理(Prepressing),编译(Compilation),汇编(Assembly)和连接(Linking),如下图所示:
1.预编译
   源代码文件hello.c和相关的头文件,例如stdio.h等被预编译器cpp预编译成一个.i文件。第一步预编译的过程相当于如下命令(-E表示只进行预编译)
   $gcc -E hello.c -o hello.i
  编译过程主要处理那些源代码文件中的以“#”开始的预编译指令,比如“#include”,“#define”等,主要处理规则如下:
  • 将所有的“#define”删除,并且展开所有的宏定义。
  • 处理所有条件预编译指令,比如“#if”"#ifdef" "#elif" "#else" "#endif"。
  • 处理“#include”预编译指令,将被包含的文件插入到该编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
  • 删除所有的注释“//”和“/**/”
  • 添加行号和文件名标识,比如#2 “hello.c”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能显示行号。
  • 保留所有的#pragma编译器指令,因为编译器需要使用它们。
经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件中,所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。
2.编译
   编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件。编译过程相当于如下命令:
   $gcc -S hello.i -o hello.s
   实际上gcc这个命令只是这些后台程序的包装,它会根据不同的参数要求去调用预编译编译程序cc1,汇编器as,连接器ld。
3.汇编
   汇编器是将汇编代码转换成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了,“汇编”这个名词也来源于此,上面的汇编过程可以调用汇编器as来完成:
   $as hello.s -o hello.c 或 $gcc -c hello.c -o hello.o
4.连接
   连接器ld产生一个正常运行的Hello World程序如下所示:


版权声明:本文为tao546377318原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。