for()和while()之间是否有任何性能差异?

时间:2009-05-11 12:29:01

标签: c++ c performance for-loop while-loop

还是所有关于语义的东西?

16 个答案:

答案 0 :(得分:63)

简短回答:不,它们完全一样。

猜测它理论上可能依赖于编译器;一个真正破碎的人可能会做一些略有不同的事情,但我会感到惊讶。

只是为了好玩,这里有两个变体,使用Ubuntu附带的x86 gcc版本4.3.3编译为完全相同的汇编代码。您可以使用linux上的objdump检查最终二进制文件上生成的程序集。

int main()
{
#if 1
    int i = 10;
    do { printf("%d\n", i); } while(--i);
#else
    int i = 10;
    for (; i; --i) printf("%d\n", i);
#endif
}

编辑:这是一个“橙子与橘子”,而循环示例也编译成同样的东西:

    while(i) { printf("%d\n", i); --i; }

答案 1 :(得分:14)

如果for和while循环执行相同的操作,编译器生成的机器代码应该(几乎)相同。

例如,在几年前我做过的一些测试中,

for (int i = 0; i < 10; i++)
{
...
}

int i = 0;
do
{
  ...
  i++;
}
while (i < 10);

将生成完全相同的代码,或者(和Neil在评论中指出)使用一个额外的jmp,这将无法在性能上产生足够大的差异而担心。

答案 2 :(得分:8)

没有语义差异,不需要任何编译差异。但这取决于编译器。所以我尝试使用g ++ 4.3.2,CC 5.5和xlc6。

g ++,CC是相同的,xlc不是

xlc的差异在初始循环条目中。

extern int doit( int );
void loop1( ) {
  for ( int ii = 0; ii < 10; ii++ ) {
    doit( ii );
  }
}

void loop2() {
  int ii = 0; 
  while ( ii < 10 ) {
    doit( ii );
    ii++;
  }
}

XLC输出

.loop2:                                 # 0x00000000 (H.10.NO_SYMBOL)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    st      r3,64(SP)
    l       r3,64(SP)  ### DIFFERENCE ###
    cmpi    0,r3,10
    bc      BO_IF_NOT,CR0_LT,__L40
...
enter code here
.loop1:                                 # 0x0000006c (H.10.NO_SYMBOL+0x6c)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    cmpi    0,r3,10    ### DIFFERENCE ###
    st      r3,64(SP)
    bc      BO_IF_NOT,CR0_LT,__La8
...

答案 3 :(得分:7)

while循环测试中变量的范围比for循环标题中声明的变量范围宽。

因此,如果将性能影响作为保持变量更长时间存在的副作用,那么在while和for循环之间进行选择时会产生性能影响(并且不会在{}中包含while以减少变量范围)。

一个示例可能是并发集合,它计算引用它的迭代器数量,如果存在多个迭代器,它会应用锁定以防止并发修改,但是如果只有一个迭代器引用它则优化锁定。如果你在一个函数中有两个for循环,在同一个容器上使用不同名称的迭代器,则会采用快速路径,但是如果有两个while循环,则会采用慢速路径。同样,如果对象很大(更多缓存流量)或使用系统资源,可能会对性能产生影响。但我想不出一个我见过的真正的例子,它会产生什么影响。

答案 4 :(得分:6)

使用循环展开优化的编译器可能只在for-loop情况下这样做。

答案 5 :(得分:5)

两者都是等价的。这是语义问题。

唯一的区别可能在于do ... while结构,你推迟评估条件直到主体之后,因此可以节省1次评估。

i = 1; do { ... i--; } while( i > 0 ); 

而不是

for(  i = 1; i > 0; --i )
{ ....
}  

答案 6 :(得分:4)

我写编译器。我们将所有“结构化”控制流(ifwhileforswitchdo ... while)编译为条件和无条件的分支。然后我们分析控制流图。由于C编译器无论如何都必须处理通用goto,因此最简单的方法是将所有减少为分支和条件分支指令,然后一定要妥善处理这种情况。 (C编译器不仅要做好手写代码,还要做自动生成的代码,这些代码可能有很多goto语句。)

答案 7 :(得分:3)

没有。如果他们正在做相同的事情,他们将编译成相同的代码 - 正如你所说,它是关于语义。选择最能代表您要表达的内容的那个。

答案 8 :(得分:3)

理想情况下它应该是相同的,但最终它取决于您的编译器/解释器。当然,您必须测量或检查生成的汇编代码。

证明可能存在差异:这些行使用cc65生成不同的汇编代码。

for (; i < 1000; ++i);   
while (i < 1000) ++i;

答案 9 :(得分:1)

在Atmel ATMega上,while()比()更快。为什么在AVR035中解释了这一点:AVR的高效C编码。

P.S。原始平台没有被提及。

答案 10 :(得分:1)

继续 时的行为方式不同:在 中,它会改变计数器,在虽然,但通常不会

答案 11 :(得分:1)

添加另一个答案:根据我的经验,优化软件就像是一个被人剃掉的大而浓密的胡须。

  • 首先,你用剪刀将它大块砍掉(在整个树上修剪整个肢体)。
  • 然后用电动剪刀(调整算法)缩短它。
  • 最后你用剃刀剃掉它以摆脱最后一点(低级优化)。

最后一个是for()while()之间的差异,但可能不会产生影响。

P.S。我认识的程序员(他们都很好,我怀疑是一个有代表性的样本)基本上是从另一个方向去做。

答案 12 :(得分:0)

就性能而言,它们是相同的。我倾向于在等待状态更改(例如等待缓冲区被填充)时使用while而在处理多个离散对象时(例如遍历集合中的每个项目)使用for

答案 13 :(得分:0)

在某些情况下存在差异。

如果您处于这种差异的重要位置,您需要选择更好的算法或开始使用汇编语言进行编码。相信我,在汇编中编码比修复编译器版本更好。

答案 14 :(得分:0)

while()for()更快/更慢?让我们回顾一下有关优化的一些事情:

  • 编译器编写器通过减少对跳转,比较,递增以及它们生成的其他类型指令的调用来非常努力地削减周期。

  • 另一方面,调用指令会消耗更多的周期,但编译器几乎无能为力去除它​​们。

  • 作为程序员,我们写了很多函数调用,有些是因为我们的意思是,有些是因为我们很懒,有些是因为编译器将它们滑入而没有显而易见。

  • 大多数时候,没关系,因为硬件太快了,而且我们的工作很小,以至于电脑就像一只小猎犬,狼吞虎咽地吃着她的食物,并乞求更多。

  • 然而,有时候,工作量很大,以至于性能成为一个问题。

  • 那我们该怎么办?哪个是更大的回报?

    • 让编译器在循环中减少几个周期&amp;这样?
    • 查找不是 -really - 的函数调用需要这么多吗?
  • 编译器无法执行后者。只有我们程序员才能。

  • 我们需要学习或教会如何做到这一点。它不是自然而然的。 我们先天倾向于做出错误的猜测,然后押注于他们。 获得更好的算法是一个开始,但只是一个开始。我们的老师需要教这个,如果确实他们知道如何。

  • Profilers是一个开始。 I do this.

当被问及为什么要抢劫银行时,Willie Sutton的虚伪引用?
因为那是钱的所在。

如果您想保存周期,请找出它们的位置。

答案 15 :(得分:-4)

可能只是编码风格。

  • 如果您知道迭代次数。
  • 如果您不知道迭代次数。