关于C ++编译器的几个问题:GCC,MSVC,Clang,Comeau等

时间:2011-03-16 09:01:32

标签: c++ visual-c++ gcc compiler-construction clang

我对C ++编译器的问题很少

  • C ++编译器是否需要one-pass compiler?标准是否在任何地方谈论它?

  • 特别是GCC单程编译器?如果是,那么为什么它会在this example中生成以下错误两次(尽管每个错误消息中的模板参数不同)?

      

    错误:声明'加法器< T> item'阴影参数
      错误:声明'加法器< char [21]> item'隐藏参数

更一般的问题


有用的链接:

5 个答案:

答案 0 :(得分:5)

该标准没有规定任何有关的要求 如何实现编译器。但你是什么意思 “一通”?今天大多数编译器只读取输入文件 一旦。他们创建了一个内存表示(通常在... 某种解析树的形式),并且可以进行多次传递 在那之上。几乎可以肯定的是,多次传递零件 它的。编译器必须对内部进行“传递” 每次实例化时模板的表示形式 例;没有办法避免这种情况。 G ++也有 在模板定义之前,在模板之前“传递” 实例化,然后报告一些错误。 (标准 委员会明确地设计了模板,允许最多 定义时的错误检测。这是 某些类型名称要求背后的动机 例如。)即使没有模板,编译器也会 通常必须在类定义上进行两次传递 有定义的功能。

关于更普遍的问题,我想你也是 必须通过“一次通过”确切地定义你的意思。我不 知道今天任何读取源文件的编译器 时间,但几乎所有人都会访问中的部分或全部节点 不止一次解析树。这是一次通过还是多通?该 在记忆不是这样的时候,区别在过去更为重要 足以在内部维护大部分源代码 表示。像Pascal这样的语言,在较小的程度上 C,有时设计为易于实现单一 传递编译器,因为单传递编译器会 明显更快。今天,这个问题基本上无关紧要, 现代语言,包括C ++,往往会忽略它;哪里 C ++似乎符合单通道编译器的需要,它是 主要是出于C兼容性的原因,以及在哪里 C兼容性不是问题(例如在类定义中),它 经常使声明的顺序无关紧要。

答案 1 :(得分:3)

据我所知,30年前编译器是一次通过很重要,因为对磁盘(或磁带)的读写速度非常慢,并且没有足够的内存来保存整个代码(感谢James观世)。此外,单通道是脚本/交互式语言的必要条件。

现在的编译器通常不是一次性的,有几个中间表示(例如Abstract Syntax TreeStatic Single Assignment Form),代码被转换成然后进行分析/优化。

如果没有一些中间步骤,C ++中的某些元素无法解决,例如:在类中,您可以引用稍后在类主体中定义的成员。此外,所有模板都需要以某种方式记住,以便在实例化期间进一步访问。

通常会发生什么,是源代码没有多次解析---没有必要这样做。因此,您不应该多次报告相同的语法错误。

答案 2 :(得分:2)

  1. 不,如果你找到一个使用频繁的C ++单通道编译器,我会感到惊讶。
  2. 不,它会根据您传递的标记执行多次传递甚至不同的优化。
  3. 优势(单程):快!因为只有在编译阶段(从而开始执行)可以非常快速地发生时才需要检查所有源。它也是一个很有吸引力的模型,因为它使编译器易于理解,并且通常“更容易”实现。 (我曾经使用过一次Pascal编译器,但是不经常遇到它们,而单通道解释器很常见)

    缺点(sinlge-pass):优化,语义/句法分析。有时单个代码看起来可以通过多次传递中的简单机制轻松捕获。 (为什么我们有像JSLint这样的东西)

    优点(多遍):优化,语义/句法分析。即使像“JRuby”这样的伪解释语言也会在执行之前通过管道编译过程来获取java / jvm字节码,你可以考虑这个多次传递,多次查看代码的变化表示(以及由此产生的优化)可以使它非常快。

    缺点(多遍):复杂性,有时是时间(取决于是否将AOT / JIT用作编译方法)

    此外,单通在学术界很常见,以帮助学习编译器设计的各个方面。

答案 3 :(得分:1)

编译器只需要自上而下查看源代码,但这并不意味着它不必多次处理已解析的内容。特别是对于模板,它必须实例化带有类型的模板化代码,并且在模板被使用(或由用户显式实例化)之前不会发生,这是重复错误的原因:

定义模板后,编译器会检测到错误,此时类型尚未被替换。当实际实例化发生时,它替换模板参数并处理结果,这是触发第二个错误的结果。请注意,如果模板在第一个定义之后以及实例化之前是专用的,则对于该特定类型,不需要发生第二个错误。

答案 4 :(得分:1)

第一个C ++编译器的开发人员Walter Bright表示他认为在没有至少3次传递的情况下编译C ++是不可能的。而且,是的,这意味着3次全文转换遍历源,而不仅仅是遍历内部树表示。请参阅his Dr. Dobb's magazine article,“为什么C ++编译速度如此之慢?”所以找到真正的一次通过编译器的任何希望似乎注定要失败。 (我认为这是Bright必须开发D,他的C ++替代品的动机的一部分。)