小C代码优化(黑客):今天没用?

时间:2012-11-29 13:17:36

标签: c compiler-optimization

20年前,(几乎)没有任何编译器优化。所以,我们开始使用一些黑客,例如:

  1. 使用指针,而不是数组索引。
  2. 不要使用小函数(例如swap()),使用宏或直接编写代码。
  3. 今天,我们有复杂的编译器优化。数组索引和指针是相同的。如果我们使用-O3(我知道,这很危险),编译器将删除除main()之外的所有函数。

    那么,旧书中的小黑客(编程珍珠 C编程语言)今天没用了?他们只是让代码更难以理解?

4 个答案:

答案 0 :(得分:6)

编程Pearls 是关于算法级别的优化,而不是代码级别的优化,因此它今天仍然具有高度相关性。

代码微观优化是另一个故事,许多旧技巧现在都是多余的甚至是有害的。目前仍有一些重要技术可用于性能关键代码,但这些技术在未来某些时候也可能变得多余/有害。您需要及时了解CPU微架构和编译器技术的进步,并且只使用适当的东西(并且只有当绝对需要时 - 过早优化才是所有邪恶的根源。)

答案 1 :(得分:1)

“使用指针,而不是数组索引。”

这从未如此高效。甚至old drafts of ANSI-C也指出它们是等价的:

  

3.3.2.1数组下标

     

下标运算符[]的定义是E1 [E2]与...相同   (*(E1 +(E2)))

“不要使用小函数(如swap()),使用宏或直接编写代码。”

这已经过时了一段时间。 C99引入了内联关键字,但在此之前,编译器可以自由地内联部分代码。由于效率原因,今天编写类似函数的宏是没有意义的。

“那么,旧书中的小黑客(编程珍珠,C编程语言)今天没用了?他们只是让代码更难以理解?”

请注意,此处的内容仅仅是我个人的意见,而不是世界程序员社区的共识:我个人会说这两本书不仅无用,而且有害。不是因为各种优化技巧,而是主要是因为可怕的,难以理解的编码风格以及对不良定义的行为的严重依赖。这两本书都充满了错误和错别字,所以如果没有你旁边的勘误表,你甚至无法阅读它们。

答案 2 :(得分:0)

如果不允许因任何原因启用优化,那些黑客仍然有用。有时编译器也无法优化代码,因为他不知道某段代码的预期和无需副作用。

这实际上取决于您的要求。根据我的经验,你仍然可以用更好的方式表达,以使编译器更好地理解你的意图。为了获得更好的编译结果,牺牲可读性总是一种权衡。

答案 3 :(得分:0)

基本上,是的。但是,如果您确实找到了错过优化机会的特别荒谬的例子,那么您应该向开发人员报告!

Braindead源代码总是会生成脑machine机器代码:在某种程度上,编译器仍然必须你所说的,而不是你的意思,尽管很多常见的习语是被识别和“修复的”(规则是,如果不使用调试器,它就不可能被告知它被改变了。)

然后仍有一些新旧技巧,至少在一些架构上是有用的。

例如,如果你有一个从0到100的循环并对数组做某事的循环,一些编译器可能会反转计数器并使其从100减少到零(因为与零比较比对另一个常数更便宜),但如果循环有副作用,他们不能这样做。如果您不关心副作用是否以相反的顺序发生,那么如果您自己反转计数器,您可以获得更好的代码。

GCC的另一个有用技巧是__builtin_expect(expr, bool),您可以告诉编译器expr可能是truefalse,因此它可以优化分支因此。同样地,__builtin_unreachable()可以告诉GCC不会发生某些事情,因此它不必考虑它的情况。

总的来说,编译器足够好,你真的不需要关心,除非你的程序在一个微小的函数中花费90%的运行时间。 (例如,memcpy仍然通常用汇编语言编写。)