编译 c + + 文件需要很长时间与 C# 和 Java 相比。它采用编译 c + + 文件,它会运行一个正常大小的 Python 脚本比显著增加。我目前使用 VC + +,但它也同样适用于任何编译器。这是为什么?

我能想到的有两个原因被加载头文件并运行预处理器,但它似乎并不是像它应该解释为什么需要那么长时间。

2008-11-25 18:25:14
问题评论:

VC + + 支持预编译的头。使用它们将帮助。好多。

是在我种情况下 (主要是与几个类-C 没有模板) 提高大约 10 倍速度的预编译的头

@Brian 我不会使用预编译头库中但

请尝试 TinyCC,但是,它只是优化非常少

您可以使用预编译头和 c + + 代码。当您编译您的代码时,它只是更新文件的更改。这样做需要很少的时间。重新编译整个项目可能需要超过 10 倍的时间。

回答:

几个原因︰

  • 头文件︰每个单个编译单元需要成百上千的标头为 1︰ 加载,并且 2︰ 编译。每一种通常为每个编译单元重新编译,因为预处理器确保编译的标头的结果可能随每个编译单元。(宏可能被定义在一个编译单元的更改标头的内容)。

    这可能是因为它需要大量代码为每个编译单元,要编译主要原因,此外,每个标头中包含要编译多个时间 (一次为每个编译单元中包括该元件)

  • 链接︰一旦经过编译,所有对象文件都都链接在一起。这基本上是不能很好地进行并行化,并具有处理整个项目的整体进程。

  • 分析︰语法分析非常复杂,很大程度取决于上下文,很难区分。这会占用大量时间

  • 模板︰在 C# 中,List<T>是列表的在编译时,无论在您的程序中有多少实例化的唯一类型。C + + 中vector<int>vector<float>,完全不同的类型,每个需要单独编译。

    添加到此,模板组成完整执行完成"子语言"编译器具有解释,并且这会变得十分复杂。即使相对较简单的模板元编程代码可以定义递归模板创建几十个模板实例化。模板还可能会导致极其复杂类型,众口长名称,链接器增加大量额外的工作。(它比较大量的符号名称,并且如果这些名称可以增长到多几千个字符,它会变得相当昂贵)。

    和当然,它们加剧头文件中的问题,因为模板通常需要在标头,这意味着目前更多的代码进行分析和编译为每个编译单元。在纯 C 代码中,标头通常只包含前向声明,但很少实际代码。C + + 中不少见的几乎所有代码驻留在头文件中。

  • 优化︰C + + 允许一些非常明显的优化。C# 或 Java 不允许类可以完全消除 (他们一定要有为了反射),但即使简单的 c + + 模板好处可以轻松地生成数十或数百类,它们都是内联和消除在优化阶段中再次。

    此外,c + + 程序必须完全由编译器优化。C# 程序可以依赖于 JIT 编译器执行额外的优化,在加载时,c + + 没有得到任何这种"第二个机会"。编译器会生成什么是为优化,因为它将会变的。

  • 机器代码︰C + + 编译为机器代码,这可能比字节码 Java 或.NET 使用 (尤其是在 x86) 变得有些复杂。
    (这被提及完整性不只是因为它提到在评论等。在实践中,这一步是不太可能将更多比总的编译时间有极小一部分。

这些因素大部分由实际上非常高效地编译的 C 代码共享。分析步骤是 c + + 中更复杂,可能要花更多的时间,但主要的罪犯可能是模板。它们是有用的并使 c + + 强大得多的语言,但它们也会其收费在条款的编译速度。

关于点 3: C 编译为 c + + 比有明显更快。它肯定是导致拥堵,并不是代码生成的前端。

关于模板︰ 矢量 < int > 必须从向量 < 双 > separatedly 编译不仅矢量 < int > 重新编译使用该每个编译单元中。通过链接器消除了冗余的定义。

dribeas︰ 为真,但不是特定的模板。内联函数或其他标头中定义的任何内容将重新编译包含它的无处不在。但是,是的尤其是痛苦与模板。:)

@configurator: Visual Studio 和 gcc 都允许为预编译头,可以为编译带来一些严重的 speed-ups。

@ColeJohnson︰ 但这是与其他任何语言没有什么不同。我已尝试为那些 c + + 的唯一列表对象

减速并不一定与任何编译器相同。

我没有使用 Delphi 或 Kylix 但回在 MS-DOS,Turbo Pascal 程序将编译几乎在瞬间完成,而等效的 Turbo c + + 程序只需将爬网。

两个主要的区别是非常强的模块系统并允许单个传递编译语法。

它是完全可以编译速度只是还没有 c + + 编译器开发人员来说,优先考虑,但也有一些固有在 C/c + + 语法复杂使它更难以处理。(我不是在 C 中,一位专家但 Walter 亮了,和他创建的 D 语言构建各种专业的 C/c + + 编译器后。他的更改之一是实施免上下文的语法,能够使语言更易于分析。)

此外,您会注意到,通常生成文件的设置,以便每个文件单独编译的 C,因此,如果所有的 10 个源代码文件使用相同的包含文件,包含文件处理 10 倍。

非常有趣的事比较 Pascal,因为 Niklaus Wirth 使用编译器将编译本身作为一个基准设计他的语言和编译器时所花费的时间。还有一篇文章,仔细书写符号快速查找的模块之后, 他替换为简单的线性搜索因为减少的代码大小所做的编译器编译本身速度更快。

分析和代码生成是实际而快速。真正的问题是打开和关闭文件。请记住,即使有包括保卫编译器仍然打开。H 文件并读取每行 (和再理会)。

朋友一次,虽然在工作无聊),利用其公司的应用程序,并一切 — 所有源文件和头文件,放入一个大文件。编译时间从 3 小时减少到 7 分钟。

文件访问确实有一只手在这,但如 jalf 所说,这样做的主要原因将是停下手中的即许多、 许多、 许多 (嵌套) ! 头文件的重复分析,完全降用例中。

此时,是您的朋友需要设置预编译头,中断不同的头文件 (尝试避免包括另一个标头,而是向前声明) 之间的相关性并获得一个更快的硬盘。该搁置,非常了不起的跃点数。

如果整个头文件 (除了可能的意见和空行) 位于头临界条件,gcc 是能够记住该文件并跳过它,如果定义了正确的符号。

分析是件大事。对于 N 对同样大小的源/头文件的相互依赖关系,有 O(N^2) 通过头文件。关闭该重复分析切削时将所有文字都放入单个文件。

小便笺︰ 包括保护防止每个编译单元的多个 parsings。不能依据多个 parsings 整体。

另一个原因是 C 预处理器将用于定位声明。甚至用头保卫.h 仍有反复,每次它们包括分析。有些编译器支持可以帮助您完成此操作,请的预编译的头,但他们始终未使用。

另请参见︰ c + + 经常质疑的答案

我认为您应该以预编译的头,要找出您的答案此重要组成部分的注释。

如果整个头文件 (除了可能的意见和空行) 位于头临界条件,gcc 是能够记住该文件并跳过它,如果定义了正确的符号。

@CesarB︰ 它仍不得不在每个编译单元 (.cpp 文件) 的完整一次对其进行处理。

C + + 编译为机器代码。因此必须预处理器、 编译器、 优化程序和最后组装器,它们都必须运行。

Java 和 C# 编译成字节的代码/IL 和 Java 虚拟机/.NET Framework 执行 (或 JIT 编译为机器代码) 之前执行。

Python 是一种解释的语言,也会被编译成字节码。

我敢肯定有其他原因,但一般情况下,无需编译到本机语言可以节省时间。

添加通过预先处理的成本是微不足道的。主要"其他原因"降低是使公共标头处理转移和重新编译被拆分为多个独立任务 (每个对象文件的一个)。这是最坏的情况,与大多数其他语言 o (n) 分析时的 O(N^2)。

此外,链接花费的时间,合适吗?

您可以从相同的 argumentation 告诉,C,Pascal 等编译器,这是很慢的这并不是平均。它有更多地使用 c + + 的语法和 c + + 编译器包含维护的巨大状态。

C 很慢。它还受到了相同的标题分析问题,如被接受的解决方案。如采取的简单 windows GUI 程序中几个编译单元,包含 windows.h 并添加 (短) 编译单元测量编译性能。

内容来源于Stack Overflow Why does C++ compilation take so long?
请输入您的翻译

Why does C++ compilation take so long?

确认取消