为什么不总是使用编译器优化?

mta*_*med 33 compiler-construction compiler-optimization

我前面问过的一个问题是未定义的行为,因此编译器优化实际上导致程序中断.

但是如果代码中没有未定义的行为,那么有没有理由不使用编译器优化?我理解有时候,出于调试目的,可能不需要优化代码(如果我错了请纠正我).除此之外,在生产代码上,为什么不总是使用编译器优化?

另外,是否有理由使用,-O而不是-O2-O3

kfm*_*e04 30

如果没有未定义的行为,但是存在明确的破坏行为(确定性正常错误,或者像竞争条件那样不确定),关闭优化是值得的,因此您可以使用调试器逐步执行代码.

通常情况下,当我达到这种状态时,我喜欢组合:

  1. 调试构建(没有优化)并逐步执行代码
  2. 向stderr 撒上诊断语句,以便我可以轻松跟踪运行路径

如果bug更加狡猾,我会拔出valgrinddrd,并根据需要添加单元测试,以便隔离问题并确保在找到问题时,解决方案按预期工作.

在极少数情况下,调试代码有效,但发布代码失败.当这种情况发生时,几乎总是,问题出现在我的代码中; 发布版本中的积极优化可以揭示由于对临时工作的错误理解生命周期等引起的错误......但即使在这种情况下,使用调试版本也有助于隔离问题.

简而言之,专业开发人员构建和测试调试(非优化)和发布(优化)二进制文件的原因有一些很好的理由.恕我直言,同时拥有调试和发布版本的单元测试将为您节省大量的调试时间.

  • 包含数据竞争的程序具有未定义的行为(`§1.10/ 21`). (4认同)
  • 此外,在调试大型程序时,高优化级别可能需要更长的时间来编译。 (2认同)

Man*_*rse 23

编译器优化有两个缺点:

  1. 优化几乎总是重新排列和/或删除代码.这将降低调试器的有效性,因为源代码和生成的代码之间不再存在1对1的对应关系.堆栈的某些部分可能会丢失,并且逐步执行指令可能会以违反直觉的方式跳过部分代码.
  2. 执行优化通常很昂贵,因此在启用优化的情况下编译需要更长时间才能进行编译.在编译代码时很难做任何有效的工作,因此显然缩短编译时间是件好事.

-O3执行的某些优化可能会导致更大的可执行文件.在某些生产代码中可能不需要这样做.

不使用优化的另一个原因是您使用的编译器可能包含仅在执行优化时才存在的错误.没有优化的编译可以避免这些错误.如果您的编译器确实包含错误,则更好的选择可能是报告/修复这些错误,更改为更好的编译器,或编写完全避免这些错误的代码.

如果您希望能够对已发布的生产代码执行调试,那么不优化代码也是一个好主意.


Dig*_*oss 8

3个理由

  1. 有时,它会混淆调试器
  2. 它与某些代码模式不兼容
  3. 不值得:缓慢或错误,或占用太多内存,或产生太大的代码.

在案例2中,想象一些故意更改指针类型的操作系统代码.优化器可以假设无法引用错误类型的对象,并生成代码来更改寄存器中的内存值,并获得"错误的" 1答案.

案例3是一个有趣的问题.有时优化程序会使代码变小,但有时会使代码更大.大多数程序都不受CPU限制,即使是那些程序,只有10%或更少的代码实际上是计算密集型的.如果优化器有任何缺点,那么只有不到10%的程序才能获胜.

如果生成的代码较大,则它对缓存不太友好.对于在微小环路中具有O(n 3)算法的矩阵代数库,这可能是值得的.但对于具有更典型时间复杂度的事物,溢出缓存实际上可能会使程序变慢.通常情况下,优化器可以针对所有这些内容进行调整,但是如果程序是Web应用程序,那么,如果编译器只执行通用程序并且允许开发人员不打开它,那么它肯定会更适合开发人员.花哨的技巧潘多拉的盒子.


1.这些程序通常不符合标准,因此优化器在技术上是"正确的",但仍然没有做开发人员的意图.