g ++编译器的内部工作原理,适用于假人

时间:2013-10-05 03:10:19

标签: c++ compiler-construction g++

在使用g ++编译C / C ++代码时,我对非常基本了解编译阶段,但我想要确认,澄清和额外的智慧珍珠。

对于这组文件:

main.c
foo.h
foo.c
bar.h
bar.c

这些来电执行以下操作......

g++ -c foo.c
g++ -c bar.c
g++ -c main.c

头文件现已添加到源文件中,所有这些.c文件都编译成.o文件。

g++ -o main.out main.o foo.o bar.o

现在所有的.o文件都链接在一起,形成一个可执行文件 - main.out

1 个答案:

答案 0 :(得分:9)

将.c文件编译成目标文件,然后将其链接到最终二进制文件中。对象文件基本上是未完成的二进制文件(它们包含.c文件中定义的函数的编译机器代码等。)

.c文件,在编译期间,包含头文件,它们基本上只是在#include指令所在的位置扩展。从这个意义上讲,.c文件是独立的,并且不需要单独编译头文件;它们都是单个翻译单元的一部分,它将变为单个目标文件。

编译的第一步是运行预处理器;这是一个花哨的文本操纵器,它处理以#开头的所有行(因此,它会扩展#include指令和条件#ifdef等等。)

然后,翻译单元的文本是标记化(这称为词法分析):字节变成最简单的可识别标记,例如'。'成为DOT,'++'成为单个'INCREMENT',关键字被识别,变量名称被解析为整个实体(标识符)。令牌仍然没有意义,但它们比字节流更容易使用。

下一个逻辑步骤,称为语法分析,根据语言的语法(语法)将标记流转换为抽象结构。这是报告语法错误的地方。例如,int a = 3;可能被解析为声明(sym(a),expression(constint(3)))。

之后的下一个逻辑步骤是语义分析,它为句法结构赋予了意义 - 例如,解析器可能会生成20个具有相同名称的变量声明,但在语义上这没有任何意义。这里报告了更多错误,例如不从所有控制路径返回的非void函数。

最后,存在代码生成步骤,其选择低级CPU指令以执行翻译单元的语义结构。这实际上是一个巨大的“步骤”,可能包括对语义数据结构(通常以抽象语法树或AST的形式)进一步转换为更低级别( intermediate )生成最终指令代码之前的表示。

在实践中,这些过程中的一些被组合(例如,在句法分析阶段期间,标记化通常按需发生,其也可以构建具有语义意义的符号表等)。还有各种优化(一些集成,一些在单独的通道中)洒满了整个。我相信GCC会将程序转换为SSA中间表示,以进行数据流分析,以便更好地进行代码优化。

然后将生成的指令,全局变量和静态变量等转储到目标文件中。然后将目标文件链接一起成为可执行文件(全局变量的地址,其他,外部目标文件和动态/共享库中定义的函数此时已解析并在最终代码中修复)

这些都不是gcc特有的;这适用于大多数(所有?)C ++(和C)编译器。