我正在设计一种编程语言,我在想的一个问题是为什么编程语言需要很长时间才能编译。假设 c++ 需要很长时间,因为它需要在每次编译文件时解析和编译头文件。但是我听说预编译的头文件需要很长时间?我怀疑 C++ 不是唯一有这个问题的语言。
8 回答
One C++ specific problem that makes it horribly slow is that, unlike almost any other language, you can't parse it independently of semantic analysis.
编译是一个复杂的过程,涉及很多步骤:
- 扫描/词法分析
- 解析
- 中间代码生成
- 可能是中间代码优化
- 目标机器代码生成
- 可选的机器相关代码优化
(撇开链接。)
当然,对于较长的程序,这将需要一些时间。
Precompiled headers are way faster, as has been known at least since 1988.
The usual reason for a C compiler or C++ compiler to take a long time is that it has to #include, preprocess, and then lex gazillions of tokens.
As an exercise you might find out how long it takes just to run cpp over a typical collection of header files---then measure how long it takes to lex the output.
gcc -O uses a very effective but somewhat slow optimization technique developed by Chris Fraser and Jack Davidson. Most other optimizers can be slow because they involve repeated iteration over fairly large data structures.
语言设计确实对编译器性能有影响。C++ 编译器通常比 C# 编译器慢,这与语言的设计有很大关系。(这也取决于编译器实现者,Anders Hejlsberg实现了 C#,是最好的之一。)
尽管预编译的头文件通常会有所帮助,但 C++ 简单的“头文件”结构会导致其性能下降。C++ 是一种比 C 复杂得多的语言,因此 C 编译器通常更快。
编译不需要花很长时间:tcc编译 ANSI c 的速度足够快,可以用作解释器。
需要考虑的一些事情:
- 扫描和解析过程的复杂性。大概需要长时间的前瞻会受到伤害,上下文(与上下文无关)语言也会受到影响。
- 内部表示。构建和处理大型且功能强大的 AST 需要一些时间。大概你应该使用最简单的内部表示来支持你想要实现的特性。
- 优化。优化很麻烦。您需要检查许多不同的条件。您可能想要多次通过。所有这一切都需要时间。
它们花费的时间与花费的时间一样长,并且通常取决于您将多少无关的东西注入到编译单元中。我希望看到你更快地手动编译它们:-)
第一次编译文件时,您应该根本没有头文件。然后根据需要添加它们(并在完成时检查是否仍然需要它们)。
减少时间的其他方法是保持编译单元很小(在极端情况下,甚至到每个文件一个函数)并使用类似 make 的工具来确保您只构建需要的内容。
一些编译器(实际上是 IDE)在后台进行增量编译,因此它们(几乎)总是接近完全编译的。
我认为这里的其他答案错过了 C++ 编译速度慢的情况的一些重要部分:
.obj
将/.o
文件保存到磁盘,读回它们,然后链接它们的编译模型- 一般链接,特别是坏的慢链接器
- 过于复杂的宏预处理器
- 任意复杂的图灵完备模板系统
- 嵌套和重复包含源文件,即使使用
#pragma once
- 用户造成的碎片,将代码分成太多的文件(在极端情况下甚至到每个文件一个函数)
- 编译器中臃肿或低效的内部数据结构
- 过度膨胀的标准库,模板滥用
相比之下,这些不会减慢 C++ 编译速度:
- 扫描/词法分析
- 解析
- 中间代码生成
- 目标机器码生成
顺便说一句,优化是最大的减速之一,但它是这里唯一在某种程度上实际上是必要的减速,而且它完全是可选的。
运行 Idera RAD Studio(有免费版本)。它带有 C++ 和 Delphi。Delphi 代码的编译时间是 C++ 代码执行相同操作的时间的一小部分。这是因为 C++ 在过去的几十年里发展得非常可怕,没有太多考虑编译器的后果,因为它是由复杂的上下文决定的宏以及在某种程度上所谓的“.hpp”地狱。艾达也有类似的问题。Pascal 的 Delphi 方言从一开始就被设计为一种高效的编译语言。因此编译器和运行需要几秒钟而不是几分钟,从而使迭代调试变得快速而简单。调试编译语言的速度很慢是一个巨大的时间浪费,而且你知道什么是痛苦的!顺便说一句,安德斯在 M$ 偷走他之前也写过 Delphi!