提问人:Luchian Grigore 提问时间:1/12/2012 最后编辑:sbiLuchian Grigore 更新时间:5/2/2018 访问量:17071
C++ 程序的编译阶段是什么?
What are the stages of compilation of a C++ program?
问:
C++ 程序的编译阶段是否由标准指定?
如果是这样,它们是什么?
如果没有,那么广泛使用的编译器(我更喜欢 MSVS)的答案会很棒。
我说的是预处理、标记化、解析等。它们的执行顺序是什么,它们具体做了什么?
编辑:我知道编译,链接和预处理的作用,我最感兴趣的是其他和顺序。当然,也欢迎对这些问题的解释,因为我可能不是唯一对答案感兴趣的人。
答:
9个所谓的“翻译阶段”列在标准中(C++11中的2.2,C++03中的2.1)。[lex.phases]
标准中要求的细节各不相同:预处理分为几个阶段,因为在标准的不同点上,当定义特定行为位时,“已经完成”和“剩下要做”的内容非常重要。因此,虽然它没有告诉你如何编写词法分析器,但它给了你一个非常清晰的路线图。
另一方面,链接主要留给实现来决定它的实际实现方式,因为标准并不关心给定名称是如何查找的,只关心它指的是什么。
它也没有提供任何关于解析的细节,它只是说“生成的标记在语法和语义上进行了分析和翻译”。那是因为整个第3-15章都需要填写这个细节。
它根本没有提到解析/转换过程中的内部表示,也没有提到优化阶段——它们对编译器的设计很重要,但对标准并不重要。优化可以在不同编译器的不同位置进行。在很长一段时间里,优化几乎完全处于编译阶段,在发出目标文件之前,链接器就像一个帖子一样愚蠢。我认为现在严肃的 C++ 实现都可以在多个 TU 上至少进行一些优化。因此,“其他人”不仅被排除在标准之外,它们实际上会随着时间的推移而改变。
C++ 规范在许多方面故意含糊不清,主要是为了保持实现独立性。语言模糊的许多领域不再是一个大问题 - 例如,您通常可以依赖 8 位的字符。然而,其他问题,如使用多重继承的结构的布局,以及虚函数对类的影响,也是一个真正的问题。这些问题会影响使用不同编译器生成的代码的兼容性。C++ 的应用程序二进制接口(或 ABI)没有严格定义,因此您偶尔不得不涉足 C,这会成为问题。编写插件接口就是一个很好的例子。
同样,该标准也没有详细说明编译器应该如何构建,因为有许多关键的决策和功能可以区分编译器。例如,MSVC 可以执行部分生成(允许编辑并继续),而 GCC 则不执行。不过,一般来说,所有编译器都执行类似的阶段:预处理、语法解析、确定程序流、生成符号表以及生成一系列线性指令,这些指令随后可以链接以生成可执行文件。哦,链接这些对象文件,这通常由链接器完成。
我简要地看了一下,很难找到各个编译器的描述。我怀疑像Microsoft这样的商业编译器有很多东西,纯粹是出于商业原因。GCC 是您最好的选择,尽管 Microsoft 很乐意描述这个过程。不过,这是非常平庸的东西:编译器的工作方式几乎相同。真正的黄金在于他们如何执行这些阶段,他们使用的算法和数据结构。在这方面,我推荐这本书。几年前,我为一门大学课程买了一本全新的书,:)我从图书馆借来了大部分教科书。
C++ 程序的编译阶段是否由标准指定?
是的,也不是。
C++ 标准定义了 9 个“翻译阶段”。引用日期为 2011-02-28(在官方 C++11 标准发布之前)的 N3242 草案 (10MB PDF),第 2.2 节:
翻译语法规则的优先级由以下阶段指定 [见脚注]。
- 物理源文件字符以实现定义的方式映射到基本源字符集 (为行尾指示符引入换行符) 如果 必要。[剪]
- 删除紧跟换行符的反斜杠字符 (\) 的每个实例,将物理源行拼接到 形成逻辑源行。[剪]
- 源文件被分解为预处理标记 (2.5) 和空格字符序列(包括注释)。[剪]
- 执行预处理指令,扩展宏调用,并执行_Pragma一元运算符表达式。[剪]
- 字符文本或字符串文本中的每个源字符集成员,以及每个转义序列和通用字符名称 在字符文本或非原始字符串文本中,转换为 执行字符集的相应成员;[剪]
- 相邻的字符串文字标记是串联的。
- 分隔标记的空格字符不再重要。每个预处理令牌都转换为一个令牌。(2.7). 的 对生成的标记进行语法和语义分析,并 翻译为翻译单元。[剪]
- 翻译的翻译单元和实例化单元的组合如下:[SNIP]
- 所有外部实体引用都将被解析。链接库组件以满足对 当前翻译。所有此类转换器输出都收集到 程序映像,其中包含在其 执行环境。
[脚注]实现必须表现得像这些单独的阶段一样,尽管在实践中不同的阶段可能会折叠在一起。
正如 [SNIP] 标记所示,我没有引用整个部分,足以表达这个想法。
需要强调的是,编译器不需要遵循这个确切的模型,只要最终结果和他们一样。
阶段 1-6 或多或少对应于预处理器,7 对应于您通常认为的编译,8 对应于模板,9 对应于链接。
(C 的翻译阶段类似,但省略了 #8。
评论
gcc -E
上一个:如何有效地为 8 球比赛打台球?
下一个:#line 是什么意思?
评论