C++ 而 (1) Vs。for (;;) 有速度差异吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/885908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:47:33  来源:igfitidea点击:

while (1) Vs. for (;;) Is there a speed difference?

c++perloptimizationperformance

提问by Copas

Long version...

长版...

A co-worker asserted today after seeing my use of while (1)in a Perl script that for (;;)is faster. I argued that they should be the same hoping that the interpreter would optimize out any differences. I set up a script that would run 1,000,000,000 for loop iterations and the same number of while loops and record the time between. I could find no appreciable difference. My co-worker said that a professor had told him that the while (1)was doing a comparison 1 == 1and the for (;;)was not. We repeated the same test with the 100x the number of iterations with C++ and the difference was negligible. It was however a graphic example of how much faster compiled code can be vs. a scripting language.

一位同事在看到我while (1)for (;;)速度更快的 Perl 脚本中的使用后断言。我认为它们应该是相同的,希望解释器能够优化任何差异。我设置了一个脚本,该脚本将运行 1,000,000,000 次循环迭代和相同数量的 while 循环并记录之间的时间。我找不到明显的区别。我的同事说一位教授告诉他这是while (1)在做比较1 == 1for (;;)而不是。我们用 100 倍的 C++ 迭代次数重复了相同的测试,差异可以忽略不计。然而,这是一个图形示例,说明编译代码与脚本语言相比可以快多少。

Short version...

精简版...

Is there any reason to prefer a while (1)over a for (;;)if you need an infinite loop to break out of?

没有任何理由,更喜欢一个while (1)比一个for (;;),如果你需要一个无限循环打破了呢?

Note:If it's not clear from the question. This was purely a fun academic discussion between a couple of friends. I am aware this is not a super important concept that all programmers should agonize over. Thanks for all the great answers I (and I'm sure others) have learned a few things from this discussion.

注意:如果问题不清楚。这纯粹是几个朋友之间有趣的学术讨论。我知道这不是一个所有程序员都应该为之苦恼的非常重要的概念。感谢所有出色的回答,我(我相信其他人)从这次讨论中学到了一些东西。

Update:The aforementioned co-worker weighed in with a response below.

更新:上述同事权衡了下面的回应。

Quoted here in case it gets buried.

在这里引用以防它被掩埋。

It came from an AMD assembly programmer. He stated that C programmers (the poeple) don't realize that their code has inefficiencies. He said today though, gcc compilers are very good, and put people like him out of business. He said for example, and told me about the while 1vs for(;;). I use it now out of habit but gcc and especially interpreters will do the same operation (a processor jump) for both these days, since they are optimized.

它来自 AMD 汇编程序员。他说 C 程序员(人们)没有意识到他们的代码效率低下。不过他今天说,gcc 编译器非常好,让像他这样的人倒闭。例如,他说,并告诉我while 1vs for(;;)。我现在出于习惯使用它,但是 gcc 尤其是解释器将在这两天执行相同的操作(处理器跳转),因为它们已经过优化。

回答by bdonlan

In perl, they result in the same opcodes:

在 perl 中,它们产生相同的操作码:

$ perl -MO=Concise -e 'for(;;) { print "foo\n" }'
a  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 -e:1) v ->3
9     <2> leaveloop vK/2 ->a
3        <{> enterloop(next->8 last->9 redo->4) v ->4
-        <@> lineseq vK ->9
4           <;> nextstate(main 1 -e:1) v ->5
7           <@> print vK ->8
5              <0> pushmark s ->6
6              <$> const[PV "foo\n"] s ->7
8           <0> unstack v ->4
-e syntax OK

$ perl -MO=Concise -e 'while(1) { print "foo\n" }'
a  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 -e:1) v ->3
9     <2> leaveloop vK/2 ->a
3        <{> enterloop(next->8 last->9 redo->4) v ->4
-        <@> lineseq vK ->9
4           <;> nextstate(main 1 -e:1) v ->5
7           <@> print vK ->8
5              <0> pushmark s ->6
6              <$> const[PV "foo\n"] s ->7
8           <0> unstack v ->4
-e syntax OK

Likewise in GCC:

同样在海湾合作委员会中:

#include <stdio.h>

void t_while() {
    while(1)
        printf("foo\n");
}

void t_for() {
    for(;;)
        printf("foo\n");
}

    .file   "test.c"
    .section    .rodata
.LC0:
    .string "foo"
    .text
.globl t_while
    .type   t_while, @function
t_while:
.LFB2:
    pushq   %rbp
.LCFI0:
    movq    %rsp, %rbp
.LCFI1:
.L2:
    movl    $.LC0, %edi
    call    puts
    jmp .L2
.LFE2:
    .size   t_while, .-t_while
.globl t_for
    .type   t_for, @function
t_for:
.LFB3:
    pushq   %rbp
.LCFI2:
    movq    %rsp, %rbp
.LCFI3:
.L5:
    movl    $.LC0, %edi
    call    puts
    jmp .L5
.LFE3:
    .size   t_for, .-t_for
    .section    .eh_frame,"a",@progbits
.Lframe1:
    .long   .LECIE1-.LSCIE1
.LSCIE1:
    .long   0x0
    .byte   0x1
    .string "zR"
    .uleb128 0x1
    .sleb128 -8
    .byte   0x10
    .uleb128 0x1
    .byte   0x3
    .byte   0xc
    .uleb128 0x7
    .uleb128 0x8
    .byte   0x90
    .uleb128 0x1
    .align 8
.LECIE1:
.LSFDE1:
    .long   .LEFDE1-.LASFDE1
.LASFDE1:
    .long   .LASFDE1-.Lframe1
    .long   .LFB2
    .long   .LFE2-.LFB2
    .uleb128 0x0
    .byte   0x4
    .long   .LCFI0-.LFB2
    .byte   0xe
    .uleb128 0x10
    .byte   0x86
    .uleb128 0x2
    .byte   0x4
    .long   .LCFI1-.LCFI0
    .byte   0xd
    .uleb128 0x6
    .align 8
.LEFDE1:
.LSFDE3:
    .long   .LEFDE3-.LASFDE3
.LASFDE3:
    .long   .LASFDE3-.Lframe1
    .long   .LFB3
    .long   .LFE3-.LFB3
    .uleb128 0x0
    .byte   0x4
    .long   .LCFI2-.LFB3
    .byte   0xe
    .uleb128 0x10
    .byte   0x86
    .uleb128 0x2
    .byte   0x4
    .long   .LCFI3-.LCFI2
    .byte   0xd
    .uleb128 0x6
    .align 8
.LEFDE3:
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits

So I guess the answer is, they're the same in many compilers. Of course, for some other compilers this may not necessarily be the case, but chances are the code inside of the loop is going to be a few thousand times more expensive than the loop itself anyway, so who cares?

所以我想答案是,它们在许多编译器中都是一样的。当然,对于其他一些编译器来说,情况可能不一定如此,但是循环内的代码很可能比循环本身贵几千倍,所以谁在乎呢?

回答by Martin Cote

Using GCC, they both seem to compile to the same assembly language:

使用 GCC,它们似乎都编译为相同的汇编语言:

L2:
        jmp     L2

回答by Bill the Lizard

There's not much reason to prefer one over the other. I do think that while(1)and particularly while(true)are more readable than for(;;), but that's just my preference.

没有太多理由偏爱其中之一。我确实认为,while(1)尤其while(true)是比 更具可读性for(;;),但这只是我的偏好。

回答by Richard Corden

There is no difference according to the standard. 6.5.3/1 has:

根据标准没有区别。6.5.3/1 具有:

The for statement

for 语句

for ( for-init-statement ; conditionopt ; expressionopt ) statement

is equivalent to

相当于

{
  for-init-statement
  while ( condition ) {
    statement
    expression ;
  }
}

And 6.5.3/2 has:

6.5.3/2 有:

Either or both of the condition and the expression can be omitted. A missing condition makes the implied while clause equivalent to while(true).

条件和表达式中的一个或两个都可以省略。缺少条件使隐含的 while 子句等效于 while(true)。

So according to the C++ standard the code:

所以根据C++标准的代码:

for (;;);

is exactly the same as:

完全相同:

{
  while (true) {
    ;
    ;
  }
}

回答by sean e

The Visual C++ compiler used to emit a warning for

Visual C++ 编译器用于发出警告

while (1) 

(constant expression) but not for

(常量表达式)但不是为了

for (;;)

I've continued the practice of preferring for (;;)for that reason, but I don't know if the compiler still does that these days.

for (;;)由于这个原因,我继续采用偏好的做法,但我不知道这些天编译器是否仍然这样做。

回答by Chris Bartow

for(;;)is one less character to type if you want to go in that direction to optimize things.

for(;;)如果你想朝那个方向去优化事情,那么输入的字符就少了一个。

回答by Lutz L.

Turbo C with this old compilers for(;;)results in faster code then while(1).

带有这个旧编译器的 Turbo C 会for(;;)产生更快的代码while(1)

Today gcc, Visual C (I think almost all) compilers optimize well, and CPUs with 4.7 MHz are rarely used.

今天gcc,Visual C(我认为几乎所有)编译器优化得很好,很少使用4.7 MHz的CPU。

In those days a for( i=10; i; i-- )was faster than for( i=1; i <=10; i++ ), because compare iis 0, results in a CPU-Zero-Flag conditional Jump. And the Zero-Flag was modified with the last decrement operation ( i-- ), no extra cmp-operation is needed.

在那些日子里, afor( i=10; i; i-- )比 快for( i=1; i <=10; i++ ),因为 comparei为 0,导致 CPU-Zero-Flag 条件跳转。并且用最后一个递减操作修改了零标志( i-- ),不需要额外的 cmp 操作。

    call    __printf_chk
    decl    %ebx          %ebx=iterator i 
    jnz     .L2
    movl    -4(%ebp), %ebx
    leave

and here with for(i=1; i<=10; i++)with extra cmpl:

这里for(i=1; i<=10; i++)有额外的cmpl:

    call    __printf_chk
    incl    %ebx
    cmpl    , %ebx
    jne     .L2
    movl    -4(%ebp), %ebx
    leave

回答by Kent Fredric

For all the people arguing you shouldn't use indefinte while loops, and suggesting daft stuff like using open goto's ( seriously, ouch )

对于所有争论你不应该使用 indefinte while 循环的人,并建议使用 open goto等愚蠢的东西(严重,哎哟)

while (1) {
     last if( condition1 );
     code();
     more_code(); 
     last if( condition2 ); 
     even_more_code(); 
}

Can't really be represented effectively any other way. Not without creating an exit variable and doing black magic to keep it synced.

不能真正以任何其他方式有效地表示。并非没有创建退出变量并使用黑魔法来保持同步。

If you have a penchant for the more goto-esque syntax, use something sane that limits scope.

如果您喜欢更多 goto-esque 语法,请使用限制范围的合理方法。

flow: { 

   if ( condition ){ 
      redo flow;
   }
   if ( othercondition ){ 
       redo flow;
   }
   if ( earlyexit ){ 
       last flow;
   }
   something(); # doesn't execute when earlyexit is true 
}

Ultimately Speed is not that important

最终速度不是那么重要

Worring about how effective speed wise different looping constructs are is a massive waste of time. Premature optimization through and through. I can't think of any situation I've ever seen where profiling code found bottlenecks in my choice of looping construct.

担心不同循环结构在速度方面的有效性是在浪费大量时间。彻头彻尾的过早优化。我想不出任何我见过的情况,其中分析代码在我选择的循环构造中发现了瓶颈。

Generally its the howof the loop and the whatof the loop.

一般来说其如何循环和什么样的循环。

You should "optimize" for readability and succinctness, and write whatever is best at explaining the problem to the next poor sucker who finds your code.

您应该“优化”可读性和简洁性,并编写最能向找到您的代码的下一个可怜的傻瓜解释问题的任何内容。

If you use the "goto LABEL" trick somebody mentioned, and I have to use your code, be prepared to sleep with one eye open, especially if you do it more than once, because that sort of stuff creates horrificallyspaghetti code.

如果您使用某人提到的“goto LABEL”技巧,而我必须使用您的代码,请准备好睁一只眼闭一只眼睡觉,尤其是如果您不止一次这样做,因为这种东西会产生可怕的意大利面条式代码。

Just because you cancreate spaghetti code doesn't mean you should

仅仅因为您可以创建意大利面条式代码并不意味着您应该

回答by Hans W

From Stroustrup, TC++PL (3rd edition), §6.1.1:

来自 Stroustrup,TC++PL(第 3 版),第 6.1.1 节:

The curious notation for (;;)is the standard way to specify an infinite loop; you could pronounce it "forever". [...] while (true)is an alternative.

奇怪的符号for (;;)是指定无限循环的标准方法;你可以发音为“永远”。[...]while (true)是另一种选择。

I prefer for (;;).

我更喜欢for (;;)

回答by silverbullettt

If compiler doesn't do any optimization, for(;;)would always be faster than while(true). This is because while-statement evaluates the condition everytime, but for-statement is an unconditional jump. But if compiler optimizes the control flow, it may generate some opcodes. You can read disassembly code very easily.

如果编译器不做任何优化,for(;;)总是比while(true). 这是因为 while-statement 每次都会评估条件,而 for-statement 是无条件跳转。但是如果编译器优化控制流,它可能会生成一些操作码。您可以非常轻松地阅读反汇编代码。

P.S. you could write a infinite loop like this:

PS你可以写一个这样的无限循环:

#define EVER ;;
  //...
  for (EVER) {
    //...
  }