C++ vs C源代码的编译和执行时间
Posted
技术标签:
【中文标题】C++ vs C源代码的编译和执行时间【英文标题】:Compilation and execution time of C++ vs C source code 【发布时间】:2011-03-24 14:24:23 【问题描述】:我不确定这是一个有效的比较还是一个有效的陈述,但多年来我听到有人声称用 C++ 编写的程序通常比用 C 编写的程序需要更长的编译时间,而且应用程序编码C++ 中的运行时通常比 C 中编写的要慢。 这些陈述有任何道理吗? 除了获得 C++ 提供的 OOP 灵活性的好处之外,是否应该纯粹从编译/执行时间的角度考虑上述比较?
我希望这不会因为过于笼统或含糊而结束,这只是试图了解多年来我从许多程序员(主要是 C 程序员)那里听到的有关陈述的实际事实。
【问题讨论】:
我认为,在这个主题上进行一次小小的 Google 搜索,就会获得数万次点击,其中包括大量论文和研究论文。 @Lundin:我认为 SO 拥有一批优秀的专家,他们会根据他们的个人和专业经验提供宝贵的意见和建议。如果一个人不得不在谷歌上搜索并阅读成千上万篇文章,而不是从其他专家程序员的经验中受益,那么 SO 将毫无用处。 这个问题的问题是“C 中的同一个程序”。问题在于,在 C 中天真地实现相同的程序不会给您相同的程序。 C++ 编译器生成了更多您实际上看不到的代码,“C”程序员应该实现这些代码以使程序相同。因此,您应该在测试中添加第三个主观测量。write
一个等效的 C++/C 程序需要多长时间。给定一个非平凡的应用程序,我怀疑差异很大。
【参考方案1】:
我将回答这个问题的一个非常客观的特定部分。使用模板的 C++ 代码编译起来会比 C 代码慢。如果您不使用模板(如果您使用标准库,您可能会这样做),编译时间应该非常相似。
编辑: 就运行时而言,它更加主观。尽管 C 可能是一种较低级别的语言,但 C++ 优化器变得非常好,并且 C++ 有助于更自然地表示现实世界的概念。如果在代码中更容易表达您的需求(正如我在 C++ 中所争论的那样),那么编写更好(和更高性能)的代码通常比使用另一种语言更容易。我认为没有任何客观数据显示 C 或 C++ 在所有可能的情况下都更快。我实际上建议根据项目需要选择您的语言,然后用该语言编写。如果事情太慢,请分析并继续使用正常的性能改进技术。
【讨论】:
是的,在模板的情况下这是可以理解的,因为编译器需要生成特化。 由于过度内联(模板倾向于鼓励内联,因为所有代码都需要在标头中可用)和/或由于代码大小增加(当它们是没有内联并且链接器不够聪明,无法合并与模板的不同实例化相对应的函数但生成相同的代码,想想std::vector< int* >
和std::vector< float* >
),这可能会导致更多的缓存未命中。
@Sylvain - 用 C 语言编写它对你有什么帮助?
嗯,关于内联,在 C 语言中,这通常是您必须做出的决定。对于代码重复,您可能会定义一个处理不透明类型的算法或数据结构(想想qsort
)或存储void*
(可以在C++
中完成,但由于它不是类型安全的,因此不鼓励)。
@Sylvain - 啊,所以使用 C++ 迫使我编写更好的程序?我可以忍受这一点! :-)【参考方案2】:
相对的运行速度有点难以预测。曾经,当大多数人认为 C++ 完全是关于继承,并且大量使用虚函数(即使它们不是特别合适)时,用 C++ 编写的代码通常会慢一些比等效的 C.
对于(我们大多数人会认为的)现代 C++,相反的情况往往是正确的:模板提供了足够多的编译时灵活性,您可以经常生成比 C 中任何合理的等效代码要快得多的代码。理论上您可以总是通过编写与“扩展”模板结果等效的专用代码来避免这种情况——但实际上,这样做非常罕见,而且非常昂贵。
C++ 也倾向于写得更普遍——例如,将数据读入std::string
或std::vector
(或std::vector<std::string>
),以便用户可以输入任意数量的没有缓冲区溢出的数据或数据只是在某些时候被截断。在 C 中,很多 更常见的是看到有人只是编写了一个固定大小的缓冲区,如果你输入的更多,它要么溢出,要么被截断。显然,您为此付出了一些代价——C++ 代码通常最终使用动态分配 (new
),这通常比仅定义一个数组要慢。 OTOH,如果你写 C 来完成同样的事情,你最终会写很多额外的代码,而且它的运行速度通常与 C++ 版本差不多。
换句话说,编写 C 语言对于基准测试和一次性实用程序之类的速度明显更快是很容易的,但速度优势在必须健壮的实际代码中消失了。在后一种情况下,您通常可以期望的最好结果是 C 代码等同于 C++ 版本,老实说,即使做得很好也相当不寻常(至少是 IME)。
比较编译速度并不容易。一方面,模板可能很慢是绝对正确的——至少对于大多数编译器来说,实例化模板是相当昂贵的。在逐行的基础上,毫无疑问,C 几乎总是比 C++ 中大量使用模板的任何东西都要快。这样做的问题是,逐行比较几乎没有多大意义——10 行 C++ 可能很容易等同于数百甚至数千行 C。只要你只看在编译时(不是开发时),无论如何,平衡可能有利于 C,但肯定不几乎与最初看起来的情况一样显着。这也很大程度上取决于编译器:例如,clang 在这方面比 gcc 做得更好很多(而且 gcc 在过去几年也有了很大改进)。
【讨论】:
【参考方案3】:仅当您使用某些特定于 C++ 的功能时,C++ 与 C 的运行时间才会受到影响。与返回错误代码和直接调用相比,异常和虚函数调用会增加运行时间。另一方面,如果您发现自己在 C 中使用函数指针(例如 GTK 所做的),那么您至少已经为虚函数付出了一些代价。并且在每个函数返回后检查错误代码也会消耗时间 - 使用异常时不要这样做。
另一方面,C++ 中的内联和模板可能允许您在编译时完成大量工作——C 推迟到运行时的工作。在某些情况下,C++ 最终可能比 C 更快。
【讨论】:
如果只在适当的时候使用,异常通常会导致(非常轻微)比返回码更快的代码。【参考方案4】:如果你编译C和C++相同的代码,应该没有区别。
如果您让编译器为您完成这项工作,例如扩展模板,那将需要一些时间。如果您在 C 语言中使用剪切和粘贴或一些复杂的宏执行相同操作,则会占用您的时间。
在某些情况下,模板的内联扩展实际上会导致代码比等效的 C 代码更专业且运行更快。喜欢这里:
http://www2.research.att.com/~bs/new_learning.pdf
或者这份报告显示许多 C++ 功能没有运行时成本:
http://www.open-std.org/jtc1/sc22/wg21/docs/TR18015.pdf
【讨论】:
问题是“相同的代码”。用 C 语言编写由 C++ 程序执行的相同代码需要工程师编写更多的 C 源代码(因为该语言的额外特性)。所以“相同代码”的测试在仅仅看一个不平凡的程序时是非常主观的。 @Loki Astari:老评论,我知道,但 Bo 的字面意思可能是相同的代码 - 例如相同的文件,一次由 g++ 编译为 c++,一次由 gcc 编译为 c(当然,只有在 c 和 c++ 的交集中编写才有可能)。 @MikeMB:那么您只是在编写 C。当然,如果您编写 C 并使用 g++ 和 gcc 编译它,那么您将得到相同的代码。但是如果你这样看的话,这个问题就一点都不有趣了。 @Loki:嗯,这只是答案的一小部分,反正我没有说任何关于问题的范围。【参考方案5】:虽然这是一个老问题,但我想在这里加 5cents,因为我可能不是唯一一个通过搜索引擎找到这个问题的人。
我不能评论编译速度,但要评论执行速度:
据我所知,c++ 中只有一个特性会降低性能,即使您不使用它也是如此。此功能是 c++ 异常,因为它们阻止了一些编译器优化(这就是为什么在 c++11 中引入 noexcept
的原因)。但是,如果您使用某种错误检查机制,那么异常可能比返回值检查和大量if else
语句的组合更有效。如果您必须将错误升级到堆栈中,则尤其如此。
无论如何,如果您在编译期间关闭异常,c++ 不会引入任何开销,除非在您故意使用相关功能的地方(例如,如果您不使用虚函数就不必为多态性付费),而大多数功能根本不会引入运行时开销(重载、模板、命名空间等)。 另一方面,大多数形式的通用代码在 c++ 中将比在 c 中的等效代码快得多,因为 c++ 提供了内置机制(模板和类)来执行此操作。一个典型的例子是 c 的 qsort 与 c++ 的 std::sort。 c++ 版本通常要快得多,因为在 sort 内部,使用的比较器函数在编译时是已知的,这至少节省了通过函数查找的调用,并且在最好的情况下允许大量额外的编译器优化。
话虽如此,c++ 的“问题”在于它很容易向用户隐藏复杂性,因此看似无辜的代码可能比预期的要慢得多。这主要是由于运算符重载、多态性和构造函数/析构函数,但即使是对成员函数的简单调用也会隐藏传递的this
-指针,这也不是 NOP。
考虑运算符重载:当您在 c 中看到 *
时,您知道这是(在大多数体系结构上)单个廉价的汇编指令,而在 c++ 中,它可能是一个复杂的函数调用(考虑矩阵乘法)。这并不意味着您可以更快地在 c 中实现相同的功能,但在 c++ 中您不会直接看到这可能是一项昂贵的操作。
析构函数是类似的情况:在“现代”c++ 中,您几乎不会看到任何通过 delete 进行的显式破坏,但任何超出范围的局部变量都可能会触发对(虚拟)析构函数的昂贵调用,而无需一行代码即可表明这一点(当然忽略)。
最后,有些人(尤其是来自 Java 的人)倾向于编写具有大量虚函数的复杂类层次结构,其中对此类函数的每次调用都是隐藏的间接函数调用,很难或不可能优化。
因此,虽然对程序员隐藏复杂性通常是一件好事,但如果程序员不知道这些“易于使用”的结构的成本,它有时会对运行时产生不利影响。
作为一个总结,我想说的是,c++ 使没有经验的程序员更容易编写慢代码(因为他们不会直接看到程序中的低效率)。但是 c++ 还允许优秀的程序员比使用 c 更快地编写“好”、正确和快速的代码——这让他们有更多时间考虑真正需要的优化。
附: 我没有提到的两件事(可能我只是忘记了)是 c++ 的复杂编译时间计算能力(感谢模板和 constexpr)和 c 的限制关键字。这是因为还没有在时间紧迫的程序中使用它们中的任何一个,所以我无法评论它们的一般用途和现实世界的性能优势。
【讨论】:
【参考方案6】:C 应用程序的编译和执行速度比 C++ 应用程序快。
C++ 应用程序通常在运行时速度较慢,而且编译起来也比 C 程序慢得多。
看看这些链接:
C vs C++ (a) C vs C++ (b) Efficient C/C++ C++ Compile Time and RunTime Performance【讨论】:
我很难相信“C++ 应用程序在运行时通常较慢”。你有这个说法的证据吗? 其中一些文章已有 5-10 年的历史。几乎不再相关。 @Lundin - 如果你有 10 年的时间来研究优化器,你就不需要一场革命。 VC2010轻松击败VC2002,gcc 4.5优化比gcc 3.x好很多 @Lundin:优化方面的差异较少取决于编译器或标准,而更多地取决于代码的编写方式。 10 年前,大多数 C++ 代码使用了大量的继承和虚函数。现在,大多数 C++ 代码更多地依赖于模板,并且尽可能少地使用虚函数。这使得在编译时发生了足够多的事情,以至于 C++ 通常至少比 C 快一点。 @Jerry Coffin 今天大多数 C++ 代码都大量使用模板。继承和模板服务于两个截然不同的目的,大多数现代 C++ 都使用两者。在性能方面最重要的区别是 C++ 支持更好的封装,更好的封装带来更好的性能,因为当分析器指定热点时,您可以轻松更改实现,而无需重写整个应用程序。以上是关于C++ vs C源代码的编译和执行时间的主要内容,如果未能解决你的问题,请参考以下文章