编译C ++程序的阶段是什么?

时间:2012-01-12 10:29:12

标签: c++ compiler-construction compilation c++-faq

标准指定的C ++程序的编译阶段是什么?

如果是这样,他们是什么?

如果没有,广泛使用的编译器的答案(我更喜欢MSVS)会很棒。

我在谈论预处理,标记化,解析等。它们的执行顺序是什么,特别是它们做了什么?

编辑:我知道编译,链接和预处理是做什么的,我最感兴趣的是其他人和订单。当然,对这些的解释也受到欢迎,因为我可能不是唯一对答案感兴趣的人。

3 个答案:

答案 0 :(得分:37)

  

标准指定的C ++程序的编译阶段是什么?

是和否。

C ++标准定义了9个“翻译阶段”。引自the N3242 draft(10MB PDF),日期为2011-02-28(官方C ++ 11标准发布之前),第2.2节:

  

翻译语法规则的优先顺序由以下阶段 [见脚注] 指定。

     
      
  1. 物理源文件字符以实现定义的方式映射到基本源字符集   (引入行尾指标的换行符)if   必要。 [SNIP]
  2.   
  3. 删除反斜杠字符(\)后面紧跟一个新行字符的每个实例,将物理源代码行拼接到   形成逻辑源代码行。 [SNIP]
  4.   
  5. 源文件被分解为预处理标记(2.5)和空白字符序列(包括注释)。 [SNIP]
  6.   
  7. 执行预处理指令,扩展宏调用,并执行_Pragma一元运算符表达式。 [SNIP]
  8.   
  9. 字符文字或字符串文字中的每个源字符集成员,以及每个转义序列和通用字符名称   在字符文字或非原始字符串文字中,转换为   执行字符集的相应成员; [SNIP]
  10.   
  11. 连接相邻的字符串文字标记。
  12.   
  13. 分隔标记的空白字符不再重要。每个预处理令牌都转换为令牌。 (2.7)。该   产生的标记在语法和语义上进行分析   翻译为翻译单位。 [SNIP]
  14.   
  15. 翻译的翻译单元和实例化单元组合如下: [SNIP]
  16.   
  17. 解析所有外部实体引用。库组件被链接以满足对未定义的实体的外部引用   目前的翻译。所有这些翻译器输出都被收集到一个   程序映像,包含在其中执行所需的信息   执行环境。
  18.         

    [脚注] 实现必须表现得就像这些单独的阶段一样,尽管实际上不同的阶段可能会折叠在一起。

[SNIP] 标记所示,我没有引用整个部分,只是足以让我们了解这个想法。

要强调的是,编译器需要遵循这个确切的模型,只要最终结果就像它们那样。

阶段1-6或多或少地对应于预处理器,7对应于您通常认为的编译,8处理模板,9对应于链接。

(C的翻译阶段相似,但省略了#8。)

答案 1 :(得分:6)

9个所谓的“翻译阶段”列在[lex.phases]的标准中(2.2 + C ++ 11,2.1 in C ++ 03)。

标准中要求的细节各不相同:预处理分为几个阶段,因为它在标准中的各个点上确实具有“已经完成”的内容以及在特定行为时“待做”的内容被定义为。因此虽然它没有告诉你如何编写词法分析器,但它为你提供了一个非常清晰的路线图。

另一方面,链接主要留给实现来决定它实际是如何实现的,因为标准并不关心如何查找给定的名称,只是它所指的是什么。 / p>

它没有给出任何关于解析的细节,它只是说“所得到的标记在语法和语义上被分析和翻译”。那是因为整个第3-15章都需要填写这些细节。

在解析/翻译过程中根本没有提到内部表示,也没有提到优化阶段 - 它们对编译器的设计很重要,但它们对标准并不重要。优化可以在不同编译器的不同位置进行。很长一段时间,优化几乎完全在编译阶段,在发出目标文件之前,并且链接器作为帖子是愚蠢的。我认为现在严肃的C ++实现都可以在多个TU中进行至少一些优化。所以“其他人”不仅仅被排除在标准之外,它们实际上会随着时间而改变。

答案 2 :(得分:3)

C ++规范在许多方面都有意模糊,主要是为了保持与实现无关。很多语言含糊不清的领域不再是一个大问题 - 例如,你通常可以依赖8位字符。但是,其他问题(如使用多重继承的结构布局)是一个真正的问题,虚拟函数对类的影响也是如此。这些问题会影响与不同编译器生成的代码的兼容性。 C ++的应用程序二进制接口(或ABI)没有严格定义,因此您偶尔必须深入C,这会成为问题。编写插件界面就是一个很好的例子。

同样,该标准没有详细描述如何构建编译器,因为有许多关键决策和功能可以区分编译器。例如,MSVC可以执行部分​​构建(允许编辑和继续),GCC不会。一般而言,所有编译器都执行类似的阶段:预处理,语法分析,确定程序流,生成符号表,以及生成一系列线性指令,这些指令随后可以链接以生成可执行文件。哦,并链接这些目标文件,这通常由链接器完成。

我简要介绍一下,很难找到个别编译器的描述。我怀疑微软提供的商业编译器有很多,纯粹出于商业原因。 GCC是你最好的选择,although Microsoft is happy to describe the process.这是非常平庸的东西:编译器的工作方式几乎相同。真正的黄金在于他们如何执行这些阶段,他们使用的算法和数据结构。在这方面,I recommend this book。几年前我为大学课程买了一个全新的副本,我从图书馆借了大部分教科书:)。