C / C ++编译器优化条件语句的程度是多少?

时间:2016-11-19 01:10:17

标签: c++ c

我最近遇到过编写以下代码的情况:

for(int i = 0; i < (size - 1); i++)
{
    // do whatever
}

// Assume 'size' will be constant during the duration of the for loop

在查看此代码时,它让我想知道为每个循环如何评估for循环条件。具体来说,我很好奇编译器是否会优化掉&#39;必须为每个循环执行的任何其他算术。在我的情况下,这个代码是否会被编译为每次循环迭代都必须评估(size-1)?或者编译器是否足够聪明才能意识到&#39; size&#39;变量不会发生变化,因此它可以为每次循环迭代预先计算它。

这让我想到了一个条件语句的一般情况,这个条件语句可能指定了多于必要的操作。

作为一个例子,下面两段代码将如何编译:

if(6)

if(1+1+1+1+1+1)

int foo = 1;
if(foo + foo + foo + foo + foo + foo)

编译器有多聪明?上面列出的3种情况是否会被转换为相同的机器代码?

虽然我在,为什么不列出另一个例子。如果您在一个不会对最终结果产生任何影响的条件中进行操作,编译器会做什么?例如:

if(2*(val))

// Assume val is an int that can take on any value

在这个例子中,乘法是完全没必要的。虽然这个案例看起来比我原来的情况要糟糕得多,但问题仍然存在:编译器是否能够删除这种不必要的乘法?

问题:

  • 条件语句涉及多少优化?
  • 是否因编译器而异?

3 个答案:

答案 0 :(得分:4)

简短回答:编译器异常聪明,并且通常会优化您提出的那些案例(包括完全忽略不相关的条件)。

语言新手在真正理解C ++方面面临的最大障碍之一是,他们的代码与计算机执行的内容之间没有一对一的关系。该语言的全部目的是创建一个抽象。您正在定义程序的语义,但计算机没有责任逐行实际遵循您的C ++代码;事实上,如果它这样做,与现代计算机的速度相比,它会非常缓慢。

一般来说,除非你有理由进行微观优化(游戏开发人员会想到),否则最好几乎完全忽略这个编程方面,并相信你的编译器。在执行所需的计算之后,编写一个获取所需输入并提供所需输出的程序...并让编译器尽一切努力弄清楚物理机器将如何实现所有这些。

有例外吗?当然。有时您的要求是如此具体,以至于您比编译器更了解,并最终优化。您通常在分析并确定您的瓶颈之后执行此操作。并且也没有理由写故意愚蠢的代码。毕竟,如果你不想让你的程序复制一个50MB的矢量,那么它将复制一个50MB的矢量。

但是,假设合理的代码意味着它的样子,你真的不应该花太多时间来担心这个问题。因为现代编译器在优化时非常好,所以你试图跟上它是个傻瓜。

答案 1 :(得分:2)

  • 是的,有很多优化,而且非常复杂。
  • 根据编译器的不同而不同,它也会根据编译器选项
  • 而有所不同

检查 https://meta.stackexchange.com/questions/25840/can-we-stop-recommending-the-dragon-book-please 对于一些书籍推荐,如果你真的想了解编译器可能会做什么。这是一个非常复杂的主题。

您还可以使用-S选项(gcc / g ++)编译到程序集,以查看编译器实际执行的操作。使用-O3 / ... / -O0 / -O来尝试不同的优化级别。

答案 2 :(得分:2)

C ++语言规范允许编译器进行任何优化,导致对预期结果没有可观察到的更改。

如果编译器可以确定size是常量且在执行期间不会改变,那么它肯定可以进行特定的优化。

或者,如果编译器也可以确定循环中没有使用i(并且之后没有使用它的值),那么它只用作计数器,它可能很好地将循环重写为:

for(int i = 1; i < size; i++)

因为这可能会产生更小的代码。即使以某种方式使用此i,编译器仍然可以进行此更改,然后调整i的所有其他用法,以便可观察的结果仍然相同。

总结:一切顺利。只要可观察结果相同,编译器可能会也可能不会进行任何优化更改。