在微观优化方面,使用C语言编写部分代码是否值得,而不是使用C++?

7

我想知道在现代编译器及其优化的情况下,写一些关键代码是否仍然值得用C而不是C++来使其更快。

我知道如果类被复制而不是传递引用,或者编译器自动创建类(通常是由于重载运算符等类似情况),C++可能导致性能不佳;但对于一个好的C++开发人员来说,他们知道如何避免所有这些问题,那么还值得使用C来提高性能吗?


11
“C”是指什么?你是不是只是指避免使用C++特性,例如STL和虚函数?你可以通过使用引用传递而不是值传递来避免性能损失;这与C与C ++无关! - Oliver Charlesworth
3
我个人没有注意到那一点,组装看起来是相同的。 - Anycorn
3
使用C++编译器编译C代码(假设它仍然是有效的C代码)应该会得到几乎相同的结果。 - Oliver Charlesworth
2
正如Knuth所说,“过早优化是万恶之源”。 - chrisaycock
4
如果你愿意为了假设的绩效提升而交换生产力,那为什么不用汇编语言编写所有代码呢? - Steve Townsend
显示剩余6条评论
5个回答

18

我同意许多评论。C语法在C++中被有意支持(仅在C99方面有所分歧)。因此,所有的C++编译器都必须支持它。实际上,我认为很难再找到专用的C编译器了。例如,在GCC中,不管代码是C还是C++,你最终都会使用相同的优化/编译引擎。

真正的问题是,使用纯C代码并在C++中编译是否会导致性能损失。答案是,在所有意义上,没有。关于异常和RTTI有一些棘手的问题,但这些主要是大小变化,而不是速度变化。你很难找到一个真正对性能产生影响的例子,因此编写专用模块似乎并不值得。

使用哪些功能非常重要。在C++中,很容易因为复制语义而变得松散,并从复制内存中承受巨大的开销。根据我的经验,这是最大的成本——在C中,你也可能遭受这种成本,但我认为不会像在C++中那样容易。

虚函数调用略微比普通函数更昂贵。同时,强制内联函数比普通函数调用更便宜。在这两种情况下,更可能是从堆栈中推出/弹出参数的成本更高。虽然担心函数调用开销应该在优化过程的相当晚的时候,因为它很少是一个重要问题。

异常在抛出时的代价很大(至少在GCC中)。但设置catch语句并使用RAII与此无关。这是GCC编译器(和其他编译器)的设计,以便真正只有异常情况具有成本。

但总结一下:一个好的C++程序员不会仅仅通过将代码编写为C来使其运行更快。


非常棒的回答。我还要指出,C++0x在许多情况下通过使用右值引用来解决对象复制成本的问题。 - Nate
是的,我们都迫不及待地等待着能够编写移动构造函数的能力!这将极大地提高性能和编码的便利性。 - edA-qa mort-ora-y

10

优化! 在考虑优化之前先测量,在应用优化之前先测量,在应用优化后再次测量再次测量!

如果你必须让你的代码运行快1纳秒(因为它将被1000人使用,在未来的1000天里每个人都会使用它,那个 纳秒非常重要),可以尝试以下措施。

是的! 这是值得的 ...

  • 更改编程语言 (C++ 到 C; Python 到 COBOL; Mathlab 到 Fortran; PHP 到 Lisp)
  • 调整编译器 (启用/禁用所有-f选项)
  • 使用不同的库(甚至编写自己的库)
  • 等等
  • 等等

但是,不要忘记测量!


哦……一个和我一样的人。6瓶冰啤酒(或你喜欢的等价物)随时随地都可以享用。 - ExpatEgghead
@ExpatEgghead:完成1个;还有5个待完成。 - pmg
2
在测量之间,捕获(https://dev59.com/qnRC5IYBdhLWcg3wG9Rb#1562802)只有测量告诉你你所做的是否有所改变。它并没有告诉你应该如何修正。测量还会让你误认为小数点精度意味着什么。 - Mike Dunlavey

1

这个问题已经被回答得够多了,所以我不会再重复一遍。

简单来说,假设你已经进行了测量等操作,并且确定某个 C++(或其他)代码段的运行速度不够优化(通常意味着你没有使用正确的工具),并且你知道通过用 C 语言编写可以获得更好的性能,那么肯定值得这样做。

有一种常见的思维方式,试图从一个工具(Java 或 SQL 或 C++)中完成所有任务。这不仅是 Maslow's Hammer,而且实际上相信他们可以在 Java 等语言中编写 C 构造。这导致了各种性能问题。作为真正的专业,架构设计是将代码段放置在适当的架构位置或平台上。正确组合 Java、SQL 和 C 将提供更好的性能。这将产生一个不需要重新访问的应用程序;顺畅的执行。在这种情况下,C++ 是否实现了这些构造函数都无关紧要。


1

pmg做得很好。只需测量而不是全局假设。此外,还要这样考虑,像gcc这样的编译器将前端、中间和后端分开。因此,Fortran、C、C++、Ada等前端最终以相同的内部中间语言结束,这就是大部分优化所在。然后,通用的中间语言被转换为特定目标的汇编语言,并进行特定目标的优化。因此,当语言差异很大时,语言可能会或可能不会从前到中引入更多代码,但对于C/C++,我认为它们是相同或非常相似的。现在,二进制文件大小是另一回事,即使只有C语法,也可能会将库吸入C与C++之间的二进制文件中,这可能会导致存储和传输差异以及内存需求成本增加。同样,在这里,只需测量。

我还要补充一下测量评论,将其编译为汇编语言和/或反汇编输出,并比较您不同语言/编译器选择的结果。这可以/将补充您在测量时看到的时间差异。


0
我在想,对于现代编译器及其优化,是否仍然值得用C来编写一些关键代码以提高速度,而不是使用C++?
不需要。保持可读性。如果您的团队更喜欢C++或C,请优先考虑它 - 特别是如果它已经在生产代码中运行(没有非常好的理由不要重写它)。
我知道如果类被复制而不是通过引用传递,C++可能会导致性能下降。
那就禁止复制和赋值。
或者当编译器自动创建类时,通常会出现重载运算符和许多其他类似情况。
您能详细说明一下吗?如果您指的是模板,则它们在运行时没有额外的成本(尽管它们可能会导致额外的导出符号,从而导致更大的二进制文件)。实际上,使用模板方法可以提高性能,例如,如果否则需要进行转换。
但对于一个懂得如何避免所有这些问题的优秀C++开发人员来说,编写C代码以提高性能是否仍然值得?
根据我的经验,专业的C++开发人员可以创建更快、更易于维护的程序。

在编程中,你必须对使用(和不使用)的语言特性进行选择。如果将C++特性分解为C中可用的集合(例如,删除异常、虚函数调用、RTTI),那么你就有了一个良好的开端。如果学会使用模板、元编程、优化技术、避免类型别名(在C中变得越来越困难或冗长)等,则应该与C并驾齐驱或更快地编写程序,并且更易于维护(因为你熟悉C++)。

如果你熟悉C++的特性,就使用C++吧。它拥有许多特性(其中许多是考虑速度/成本而添加的),并且可以编写得与C一样快(甚至更快)。

通过模板和元编程,你可以将许多运行时变量转换为编译时常量,从而获得卓越的性能提升。有时这会涉及微观优化领域。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接