c++ - 为什么 C++ 编译需要这么长时间?

标签 c++ performance compilation

与 C# 和 Java 相比,编译 C++ 文件需要很长时间。编译 C++ 文件比运行正常大小的 Python 脚本花费的时间要长得多。我目前正在使用 VC++,但任何编译器都一样。这是为什么呢?

我能想到的两个原因是加载头文件和运行预处理器,但这似乎不能解释为什么需要这么长时间。

最佳答案

几个原因

头文件

每个编译单元都需要 (1) 加载和 (2) 编译成百上千个头文件。 它们中的每一个通常都必须为每个编译单元重新编译, 因为预处理器确保编译头文件的结果可能在每个编译单元之间有所不同。 (可以在一个编译单元中定义一个宏来改变头文件的内容)。

这可能是的主要原因,因为它需要为每个编译单元编译大量代码, 此外,每个头文件都必须编译多次 (每个包含它的编译单元一次)。

链接

编译后,所有目标文件都必须链接在一起。 这基本上是一个无法很好并行化的单一流程,必须处理您的整个项目。

解析

语法解析极其复杂,严重依赖于上下文,并且很难消除歧义。 这需要很长时间。

模板

在 C# 中,List<T>是唯一被编译的类型,无论您的程序中有多少 List 实例。 在 C++ 中,vector<int>是与 vector<float> 完全不同的类型,并且每个都必须单独编译。

此外,模板构成了编译器必须解释的完整图灵完备的“子语言”, 这可能会变得非常复杂。 即使是相对简单的模板元编程代码也可以定义创建数十个模板实例的递归模板。 模板也可能导致极其复杂的类型,名称长得离谱,给链接器增加了很多额外的工作。 (它必须比较很多符号名称,如果这些名称可以增长到数千个字符,那将变得相当昂贵。

当然,它们加剧了头文件的问题,因为模板通常必须在头文件中定义, 这意味着必须为每个编译单元解析和编译更多的代码。 在纯 C 代码中, header 通常只包含前向声明,但很少包含实际代码。 在 C++ 中,几乎所有代码都驻留在头文件中的情况并不少见。

优化

C++ 允许一些非常显着的优化。 C# 或 Java 不允许完全消除类(它们必须用于反射目的), 但即使是一个简单的 C++ 模板元程序也可以轻松生成数十或数百个类, 所有这些都在优化阶段再次内联和消除。

此外,C++ 程序必须由编译器完全优化。 C# 程序可以依靠 JIT 编译器在加载时执行额外的优化, C++ 没有得到任何这样的“第二次机会”。编译器生成的内容已尽可能优化。

机器

C++ 被编译成机器码,这可能比 Java 或 .NET 使用的字节码复杂一些(尤其是在 x86 的情况下)。 (这是出于完整性而提到的,只是因为在评论等中提到了它。 实际上,这一步不太可能只占用总编译时间的一小部分)。

结论

大多数这些因素都由 C 代码共享,实际上编译效率很高。 解析步骤在 C++ 中要复杂得多,并且会占用更多时间,但主要的问题可能是模板。 它们很有用,使 C++ 成为一种更强大的语言,但它们也会在编译速度方面付出代价。

关于c++ - 为什么 C++ 编译需要这么长时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/318398/

相关文章:

android - 无法分析 android native 代码

python - 计算一个数组在另一个数组中没有重叠的出现次数

python - 为什么复杂的共轭 react 如此缓慢?

c++ - 如何在 OpenMP 中设置线程数

c++ - 是否有与 Sse2 _mm_unpackhi/lo_epi32/64 和 _mm_shuffle_epi8/32 等效的 Neon?

c++ - 如何在 C++ 构建中嵌入 JSON 文件

c++ - macOS High Sierra 10.13 上损坏的 c++ 标准库

.net - 将 .NET 控制台应用程序编译为单个可执行文件

java - 在同一个包和目录中找不到符号

c++ - 将 ffmpeg 控制台输出重定向到 C++ 中的字符串或文件