“for(;;)”比“while(TRUE)”快吗?如果没有,为什么人们会使用它?

时间:2010-04-09 22:04:48

标签: c++ c optimization readability infinite-loop

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

我见过这种事情很多,但我觉得这很奇怪...... 说while(true)或类似的东西不是更清楚吗?

我猜这(因为许多程序员采用神秘的代码的原因)这是一个很小的利润吗?

为什么,真的值得吗?如果是这样,为什么不这样定义:

#define while(true) for(;;)

另见:Which is faster: while(1) or while(2)?

21 个答案:

答案 0 :(得分:252)

  1. 它并不快。
  2. 如果您真的关心,请使用您的平台的汇编程序输出进行编译,并查看。
  3. 没关系。这永远不重要。写下你喜欢的无限循环。

答案 1 :(得分:165)

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

一个是一些编译器在while(true)上产生警告(类似“循环条件不变”)。避免警告总是一件好事。

另一个是我认为for(;;)更清晰,更有说服力。 我想要一个无限循环。字面意思 没有条件,它什么都不依赖。我只是想让它永远持续下去,直到我做一些事情来摆脱它。

然而,while(true),那么,什么是真的与任何事情有关?我对循环不感兴趣,直到true变为false,这就是这个形式的字面意思(循环,而true为真)。我只是想循环。

不,绝对没有性能差异。

答案 2 :(得分:55)

我个人使用for (;;),因为其中没有任何数字,它只是一个关键字。我更喜欢while (true)while (1)while (42)while (!0)等等。

答案 3 :(得分:48)

由于Dennis Ritchie

  • 我开始使用for (;;),因为这就是Dennis Ritchie在K& R中的表现方式,在学习新语言时,我总是试图模仿聪明人。

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

  • 您的#define将无效,因为#define'd必须看起来像C标识符。

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

答案 4 :(得分:46)

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

如果你很好奇,这就是gcc 4.4.1为x86提供的内容。两者都使用x86 JMP指令。

void while_infinite()
{
    while(1)
    {
    puts("while");
    }
}

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

汇编到(部分):

.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

答案 5 :(得分:41)

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

在C ++中while (true)很好,但在C中你依赖于标题来定义true,但TRUE也是一个常用的宏。如果你使用while (1)它在C和C ++和JavaScript中是正确的,而不是Java或C#,它要求循环条件是布尔值,例如while (true)while (1 == 1)。在PHP中,关键字不区分大小写,但语言更喜欢大写TRUE

但是,for (;;)在所有这些语言中始终完全正确。

答案 6 :(得分:21)

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

在某种意义上,使用while (TRUE)可能更具可读性,我决定使用for (;;)成语,因为它突出

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

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

答案 7 :(得分:17)

我见过有些人喜欢它,因为他们在某个地方有#define:

#define EVER ;;

允许他们写这个:

for (EVER)
{
    /* blah */
}

答案 8 :(得分:16)

如果(如果您的语言支持):

start:
/* BLAH */
goto start;

答案 9 :(得分:12)

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

然而,只是为了逆转这种趋势,我认为while(TRUE)形式比(;;)更具可读性和直观性,而且可读性和清晰度是编码指南的重要原因。我听说for((;)方法的原因(我更喜欢将我的编码指南建立在可靠的推理和/或有效性证明的基础上)。

答案 10 :(得分:11)

while(true)

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

for(;;)

是首选。

答案 11 :(得分:11)

不仅仅是一个众所周知的模式,而是C(和C ++)中的标准习语

答案 12 :(得分:11)

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

int x = 0;

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

    printf("%d", x);
}

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

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)),则两者的输出都相同。两个循环都缩减为一个跳转指令。

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)  

无论您使用哪个,对于具有速度优化的合适编译器都无关紧要。

答案 13 :(得分:9)

这是个人偏好的问题,哪种方式更快。就个人而言,在编程期间,我是一个触摸键盘,从不看我的键盘 - 我可以触摸键盘上的所有104个键。

我发现如果更快输入“while(TRUE)”。

我精神上添加了一些手指移动测量并将它们总计。 “for(;;)”有大约12个键宽度的后退和第四个(主键和键之间,以及主键和SHIFT键之间) “while(TRUE)”有大约14个键宽度的后移和第四个。

然而,在输入后者时,我很容易出错。我一次用心语思考,所以我发现输入像“nIndex”这样的东西比“nIdx”这样的首字母缩略词更快,因为我必须精神拼出拼写而不是在脑海里说出来让我的手指自动 - 这个词(喜欢骑自行车)

(我的TypingTest.com基准= 136 WPM)

答案 14 :(得分:6)

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

但是 - 假设它有所作为。假设其中一个每次迭代需要3个指令。

你在乎吗?

只有你在循环中做的事情几乎没有几乎从不的情况。

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

答案 15 :(得分:5)

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

但我建议您更喜欢for(;;),原因如下:

  • 我使用过的许多编译器都会为while(true)生成一个常量表达式警告,并带有适当的警告级别设置。

  • 在您的示例中,宏TRUE可能未按预期定义

  • 无限while循环有许多可能的变体,例如while(1)while(true)while(1==1)等;所以for(;;)可能会带来更大的一致性。

答案 16 :(得分:5)

for(;;Sleep(50))
{
    // Lots of code
}

比以下更清楚:

while(true)
{
    // Lots of code
    Sleep(50);
}

如果您不使用Sleep(),则不适用。

答案 17 :(得分:4)

“永远”循环在嵌入式系统中作为后台循环很流行。有些人将其实现为:

for (; ;)
{
 // Stuff done in background loop
}

有时它实现为:

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

另一个实现是:

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

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

答案 18 :(得分:2)

我认为while(true)比(;;)更可读 - 它看起来像程序员错过for循环中的东西:)

谁在乎哪一个更快

答案 19 :(得分:2)

使用“for(;;)”的最重要原因是在进行探索性编程时担心使用“while(TRUE)”。使用“for”控制重复次数更容易,并且更容易将“for”循环转换为无限循环。

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

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

当我确定我的功能时,我将其转换为无限循环:

    for(;;) recursiveFunction(oneParam);

答案 20 :(得分:0)

正如其他人所指出的,从技术角度来看,这根本无关紧要。有些人认为一种比另一种更具可读性,他们对此有不同的看法。

对我来说,这基本上只是吹毛求疵,因为任何 C 程序员都应该能够立即while(1)for(;;) 识别为无限循环。

您的定义不起作用。但是,您可以(但不应该)这样做:

#define repeat for(;;)

int main(void)
{
    repeat {
        puts("Hello, World");
    }
}

但是真的,不要做那样的事情......