预编译、编译、汇编、链接过程

预编译

将源代码或者头文件经过预编译成一个.i文件。例如C++文件扩展名是.cpp,头文件的扩展名可能是.hpp,预编译后的文件扩展名是.i

预编译的过程相当于下面的命令:

对c语言文件的处理:gcc –E 源文件 –o目标文件

对c++语言的文件的处理:g++ gcc –E 源文件 –o目标文件

例如:gcc –E hello.c –o hello.i

预编译需要做的工作:主要处理源代码中以“#”开始的预编译命令

  1. 删除所有的#define,并且展开所有的宏定义。
  2. 处理所有预编译条件比如“#if”、“#ifdef”、“#elif”、“#else”、“endif”。
  3. 处理“#include”预编译指令,将包含的文件插入到该预处理指令的位置。这整个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
  4. 删除所有的注释“//”和“/**/”。
  5. 添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
  6. 保留所有的#pragma编译器指令,因为编译器须要使用它们。

经过预编译后的.i文件不包含任何的宏定义,因为所有的宏已经被展开,并且包含的文件也已经插入到.i文件中

 

编译

就是将预处理完的文件进行,词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件,是整个过程中的核心。

使用以下命令:

gcc –S hello.i –o hello.s

词法分析:代码被输入到扫描器,利用算法将代码分割成一系列的记号。词法分析产生的记号一般可以分为:关键字、标识符、字面量(包含数字字符串)和特殊符号(如加号、减号)。在识别记号同时,扫描器还做了其他工作,比如将标识符放入符号表,将数字、字符串常量放入文字表中。

语法分析:接下来语法分析器对记号进行语法分析,产生语法树;在c语言中每个语句其实就是一个表达式,语法树就是以表达式为节点的树。在语法分析的同时,许多符号优先级和含义也被确定下来。如果表达式错误,编译器会报出语法阶段的错误。

语义分析:语义分析由语义分析器来完成。语法分析仅仅完成了对表达式的语法层次的分析,并无法知道语句是否有意义。语义分析器只能识别静态语义;静态语义指的是在编译阶段能确定的语义,对应的动态语义指的是在运行阶段才能确定的语义;比如,将一个浮点类型赋值给指针类型,语义分析器会发现类型不匹配,编译器会报错,这是在编译期间就能识别的。像0作为除数就是在运行期间语义错误。

 

汇编

汇编器就是将汇编代码转变成可以执行的指令,每一个汇编语句对应着一条机器指令,所以汇编器过程相对简单。经过预编译、编译、汇编最终输出目标文件。

使用以下的命令:

gcc –c hello.s –o hello.o

 

链接

组装模块的过程就是链接。链接的主要内容就是处理各个模块中变量和函数的相互引用。链接过程主要包括了地址和空间分配、符号决议和重定位(当编译本文件时,编译器不知道其他文件中定义的变量,所以在没有确定地址的情况下,将目标地址置为0,当与其他文件链接起来的时候再将其地址进行修正,地址修正的过程叫做重定位)。

最基本的静态链接就是将每个模块的源代码文件经过编译得到目标文件,目标文件和库文件一起链接最终成为可执行文件。

 

猜你喜欢

转载自blog.csdn.net/QX_a11/article/details/89813315