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

hal*_*y9k -1 c++ compiler-construction g++

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

对于这组文件:

main.c
foo.h
foo.c
bar.h
bar.c
Run Code Online (Sandbox Code Playgroud)

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

g++ -c foo.c
g++ -c bar.c
g++ -c main.c
Run Code Online (Sandbox Code Playgroud)

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

g++ -o main.out main.o foo.o bar.o
Run Code Online (Sandbox Code Playgroud)

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

Cam*_*ron 9

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

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

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

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

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

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

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

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

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

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