关于c ++:“for(;;)”是否比“while(TRUE)”更快?

Is “for(;;)” faster than “while (TRUE)”? If not, why do people use it?

1
2
3
for (;;) {
    //Something to be done repeatedly
}

我见过这种东西用得很多,但我觉得很奇怪…难道说while(true)或是其他类似的话就更清楚了吗?

我猜(许多程序员使用密码的原因也是如此),这是一个小范围的更快吗?

为什么,它真的值得吗?如果是这样,为什么不直接用这种方式来定义它呢?

1
#define while(true) for(;;)

另请参见:哪个更快:while(1)或while(2)?


  • 速度不快。
  • 如果您真的很在意,可以使用平台的汇编程序输出进行编译并查看。
  • 没关系。这无关紧要。写出你喜欢的无限循环。

  • 我喜欢for(;;)有两个原因。

    一种是有些编译器在while(true)上产生警告(类似于"循环条件是常量")。避免警告总是一件好事。

    另一个原因是我认为for(;;)更清晰,更有说服力。我想要一个无限循环。它实际上没有条件,它什么也不依赖。我只希望它永远持续下去,直到我做了一些事情来摆脱它。

    而对于while(true),那么,什么是真的呢?我对循环不感兴趣,直到"真"变为"假",这就是这个形式的字面意思(循环而"真"是真)。我只想循环。

    不,绝对没有性能差异。


    我个人使用for (;;),因为里面没有数字,只是一个关键字。我比较喜欢while (true)while (1)while (42)while (!0)等。


    因为丹尼斯·里奇

    • 我开始使用for (;;),因为丹尼斯·里奇在K&R中就是这样做的,当我学习一门新语言时,我总是试图模仿聪明人。

    • 这是惯用的C/C++。如果你计划在C/C++空间中做很多事情,从长远来看,习惯它可能更好。

    • 你的#define不起作用,因为被定义的东西必须看起来像C标识符。

    • 所有现代编译器都将为这两个构造生成相同的代码。


    在任何正常的编译器中都不会更快。它们都将被编译成无条件跳转。for版本更容易输入(如Neil所说),如果您理解for循环语法,它将是清晰的。

    如果你好奇的话,这里是GCC4.4.1给我的x86版本。两者都使用x86 JMP指令。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void while_infinite()
    {
        while(1)
        {
        puts("while");
        }
    }

    void for_infinite()
    {
        for(;;)
        {
        puts("for");
        }
    }

    编译为(部分):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    .LC0:
    .string"while"
    .text
    .globl while_infinite
        .type   while_infinite, @function
    while_infinite:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
    .L2:
        movl    $.LC0, (%esp)
        call    puts
        jmp .L2
        .size   while_infinite, .-while_infinite
        .section    .rodata
    .LC1:
        .string"for"
        .text
    .globl for_infinite
        .type   for_infinite, @function
    for_infinite:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
    .L5:
        movl    $.LC1, (%esp)
        call    puts
        jmp .L5
        .size   for_infinite, .-for_infinite


    我更喜欢for (;;),因为它在不同的类C语言中是最一致的。

    在C++ EDCOX1中,5是很好的,但是在C中,你依赖于一个头来定义EDCOX1×15,而EDCOX1×15是一个常用的宏。如果你使用EDCOX1,10,它在C和C++中是正确的,而JavaScript,而不是Java或C语言,它要求循环条件是布尔的,比如EDCX1,5,EDCX1,19。在PHP中,关键字不区分大小写,但语言更喜欢大写的true

    然而,for (;;)在所有这些语言中总是完全正确的。


    我个人更喜欢for (;;)习惯用法(它将编译成与while (TRUE)相同的代码)。

    从某种意义上讲,使用while (TRUE)可能更易读,我决定使用for (;;)成语,因为它很突出。

    无限循环结构应该很容易在代码中被注意到或调用,我个人认为for (;;)样式比while (TRUE)while (1)样式做得更好。

    此外,我还记得当while循环的控制表达式是常量时,一些编译器会发出警告。我不认为这种情况发生的太多,但仅仅是虚假警告的可能性就足以让我想避免它。


    我看到有些人喜欢它,因为他们有一个这样的定义:

    1
    #define EVER ;;

    允许他们写下:

    1
    2
    3
    4
    for (EVER)
    {
        /* blah */
    }


    那(如果你的语言支持它的话)呢?

    1
    2
    3
    start:
    /* BLAH */
    goto start;


    在生成的机器代码方面没有区别。

    然而,为了顺应这一趋势,我认为while(true)形式比(;;)形式更易于阅读和直观,可读性和清晰性是编码指南的重要原因,而不是我听说的for(;)方法的任何原因(我更喜欢将我的编码指南建立在可靠的推理和/或有效性证明的基础上自我)。


    如果您的代码是由编译器优化的,那么两者应该是相同的。为了解释我所说的优化,这里有一个用MSVC 10编写的示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    int x = 0;

    while(true) // for(;;)
    {
        x +=1;

        printf("%d", x);
    }

    如果您在调试模式下构建它(没有任何优化(/od)),反汇编将显示出明显的区别。对于while中的true条件有额外的说明。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    while(true)
    00D313A5  mov         eax,1                //extra
    00D313AA  test        eax,eax              //extra
    00D313AC  je          main+39h (0D313B9h)  //extra
        {
            x +=1;
    00D313AE  mov         eax,dword ptr [x]  
    00D313B1  add         eax,1  
    00D313B4  mov         dword ptr [x],eax  
        printf("%d", x);
        ...
        }
    00D313B7  jmp         main+25h (0D313A5h)  


    for(;;)
        {
            x +=1;
    00D213A5  mov         eax,dword ptr [x]  
    00D213A8  add         eax,1  
    00D213AB  mov         dword ptr [x],eax  
        printf("%d", x);
        ...
        }
    00D213AE  jmp         main+25h (0D213A5h)

    但是,如果您在发布模式下构建代码(使用默认的最大化速度(/o2)),则两种方法的输出相同。两个循环都被简化为一个跳转指令。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    for(;;)
        {
            x +=1;
    01291010  inc         esi  

            printf("%d", x);
        ...
        }
    0129101C  jmp         main+10h (1291010h)  

        while(true)
        {
            x +=1;
    00311010  inc         esi  

            printf("%d", x);
        ...
        }
    0031101C  jmp         main+10h (311010h)

    无论您将使用哪一种,对于一个具有速度优化功能的优秀编译器来说都无关紧要。


    1
    while(true)

    使用Visual Studio生成警告(条件为常量)。我工作过的大多数地方都会编译生产版本,并将警告作为错误。所以

    1
    for(;;)

    优先考虑。


    不仅是众所周知的模式,而且是C(和C++)中的标准成语。


    这是个人喜好的问题,哪种方式更快。就我个人而言,我是一个触摸式打字员,在编程过程中从不看我的键盘——我可以触摸键盘上的所有104个键。

    我发现输入"while(true)"的速度是否更快。

    我在心里加了一些手指运动的测量值,然后把它们加起来。"for(;)"有大约12个键宽的向后和第四个移动(在主键和键之间,以及在主键和SHIFT键之间)"while(true)"有大约14个前后移动的关键宽度。

    但是,在输入后者时,我很少出错。我每次都会用文字思考,所以我发现打字"nindex"比用缩写词"nidx"更快,因为我必须在心里拼出字母,而不是在心里说出来,让我的手指自动打字(就像骑自行车一样)。

    (my typingtest.com基准=136 wpm)


    所有好的答案-行为应该完全相同。

    但是-假设它确实有影响。假设其中一个在每次迭代中多接受了3条指令。

    你应该关心吗?

    只有当你在循环中所做的几乎是什么都不是的时候,这几乎是不可能的。

    我的观点是,有微观优化和宏观优化。微观优化就像"理发减肥"。


    1
    2
    3
    4
    for(;;Sleep(50))
    {
        // Lots of code
    }

    比以下更清楚:

    1
    2
    3
    4
    5
    while(true)
    {
        // Lots of code
        Sleep(50);
    }

    如果你不使用Sleep(),这并不适用。


    我无法想象一个有价值的编译器会生成任何不同的代码。即使是这样,如果不测试更高效的特定编译器,也无法确定。

    不过,我建议您选择for(;;),原因如下:

    • 我使用的许多编译器将使用适当的警告级别设置为while(true)生成常量表达式warning。

    • 在您的示例中,宏"真"的定义可能与您期望的不同。

    • 无限while循环有许多可能的变体,如while(1)while(true)while(1==1)等,因此for(;;)可能导致更大的一致性。


    "永远"循环在嵌入式系统中作为一个背景循环很流行。有些人将其实现为:

    1
    2
    3
    4
    for (; ;)
    {
     // Stuff done in background loop
    }

    有时它被实现为:

    1
    2
    3
    4
    while (TRUE /* or use 1 */)
    {
     // Stuff done in background loop
    }

    另一个实现是:

    1
    2
    3
    4
    do
    {
     // Stuff done in background loop
    } while (1 /* or TRUE */);

    优化编译器应该为这些片段生成相同或类似的程序集代码。一个重要的注意事项:循环的执行时间并不是一个大问题,因为这些循环将永远持续下去,而处理部分将花费更多的时间。


    我假设while(true)比(;;)更可读——它看起来像是程序员遗漏了for循环中的内容:)

    谁在乎哪一个更快,如果有的话


    使用"for(;;)"最重要的原因是在进行探索性编程时害怕使用"while(true)"。使用"for"可以更容易地控制重复次数,而且更容易将"for"循环转换为无限循环。

    例如,如果正在构造递归函数,则可以在转换为无限循环之前限制对该函数的调用量。

    1
        for(int i=0;i<1000;i++) recursiveFunction(oneParam);

    当我确定了我的函数后,我把它转换成一个无限循环:

    1
        for(;;) recursiveFunction(oneParam);