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

Chr*_*per 160 c c++ optimization readability infinite-loop

for (;;) {
    //Something to be done repeatedly
}
Run Code Online (Sandbox Code Playgroud)

我已经看到这种东西使用了很多,但我觉得它很奇怪......说再说清楚while(true),还是沿着这些方向做些什么?

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

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

#define while(true) for(;;)
Run Code Online (Sandbox Code Playgroud)

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

Ben*_*tto 259

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

  • 直观地说,优化无限循环可以实现无限加速.那么,我们不会根据直觉进行编程.:-) (220认同)
  • @克里斯.在编程和生活中一样,宗教辩论只值得您花时间去做真正重要的事情.这不是其中之一.正如你所看到的,每个人都有一种编写无休止循环的宠物方式.挑选一些让你最开心的事情,然后在重要的代码上运行你的探查器.:) (7认同)
  • @Steven LOL,这很有意思,但后来考虑到你实际达到无限加速潜力的唯一场景是当循环永远不会中断并真正无限运行时,这可能是一个错误,或者如果有意的话,将是在达到那个潜力之前无限等待. (6认同)
  • 我想你是对的.我想我正陷入关于小事情的"宗教"辩论中.谢谢你让我的良心松动.:d (5认同)
  • 它确实很重要,因为某些平台上的一些早期编译器确实加载了一个常量并对其进行了条件跳转.在那些日子硬件上,确实很重要. (3认同)
  • 我用于(;;)因为while(true)将生成关于常量条件表达式的警告. (2认同)

jal*_*alf 172

我更喜欢for(;;)两个原因.

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

另一个是我认为for(;;)更清晰,更有说服力.我想要一个无限循环.它的字面没有条件,这取决于什么.我只是想让它永远持续下去,直到我做一些事情来突破它.

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

不,绝对没有性能差异.

  • +1以避免警告.但至于清晰度,我发现虽然比在这种情况下更清楚.我想这方面只取决于个人偏好. (70认同)
  • 如果`while(true)`给出警告,你的编译器很糟糕. (30认同)
  • 是的,优先和习惯.如果你不习惯看到`for(;;)`,它看起来很奇怪.但是我建议你试着习惯它,因为它*是一个常见的习语,你会再次遇到它.;) (14认同)
  • jalf关于它是惯用语的评论真的是这里的答案.它通常用于"无限循环",因为它是*在C中编写"无限循环"的常用方式.没有一个成语的充分理由 - 它只是一个自我强化的约定. (7认同)
  • @Steve:我不明白为什么我曾经*使用`for(; condition;)`.那就是while循环是*for*.但就像我说的,无限循环,我真的不希望编译器比较*any*condition.天真地,使用`while`循环,它必须在每次迭代时测试`true`(显然,即使是最笨的编译器也不会这样做,但这是困扰我的原则.它让我觉得过度指定你的代码),而使用`for(;;)`你实际上是在说"没有条件可以测试.只需循环".我发现它最接近你想象的`循环{...}` (7认同)
  • 但是,我们很清楚,这不是我强烈关注的事情.在我必须使用的代码中看到`while(true)`绝对没有问题,我认为两者都是完全可读的.我只是在解释为什么*我认为`for(;;)`更可取. (4认同)
  • 它没有条件:它是一个无条件循环.我确实想做一些"指定的次数".这个数字只是无穷大.怎么样`while`更好?你经常使用*直到*条件改变.这永远不会发生.我不关心1 == 1,或42> 0或TRUE是否为真.所有这些只是说"继续这样做"的迂回方式.所有这些*都可以放在`while`循环中以实现同样的目的.但是当我们已经有了一个特定的循环形式时,为什么要跳过所有这些箍? (3认同)
  • 他们实际上并没有删除任何其他东西......而只是将它混为一谈.`for`的所有"参数"都是可选的,所以在Go中,无限循环是`for {...}`.`for <condition> {...}`相当于一个while循环,有一个正常的三个子句用于循环,最后`for i:= range <sequence> {...}`是一个foreach循环.有道理,虽然我只使用了Go一点,所以它仍然是我的头脑,因为相同的关键字用于一切;-) (2认同)

ta.*_*.is 56

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

  • 0,1和无穷大是可接受的幻数,将0和1扩展为false并且true不是损失.`true`不再是一个神奇的数字,而'for`是一个神奇的关键词,或者`for(;;)`使用隐含的魔法无穷大.(`while(42)`确实是令人厌恶的.) (38认同)
  • 切线:我的一位CS教授说"编程中只有三个数字:0,1和n.其他任何东西都称为幻数." (38认同)
  • +1表示它不依赖于幻数. (30认同)
  • while(42)是最酷的,对于while(1)或while(true)或while(!0)没有产生不同的结果,并且具有_philosophical_含义.我想`for(;;)`无论如何都要比其他人解析得更快 (21认同)
  • 同意0和1是可接受的魔术数字. (4认同)
  • @ShinTakezou更好地`#define LIFE 42``而(LIFE)`:) (2认同)

Mar*_*son 49

因为丹尼斯里奇

  • 我开始使用,for (;;)因为这就是Dennis Ritchie在K&R中所做的事情,当我学习一门新语言时,我总是试图模仿聪明人.

  • 这是惯用的C/C++.如果您计划在C/C++空间做很多事情,那么从长远来看,它可能会更好地适应它.

  • #define将无法工作,因为#define'd必须看起来像一个C标识符.

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

  • 我听说那些新手也使用[新奇函数定义风格](http://stackoverflow.com/a/3092074/1011250). (13认同)
  • 是的,这就是你怎么知道有人从K&R学习C的方式,应该学习它的方式.每当我看到`while(TRUE)`时,我怀疑程序员是C新手,或者是从For Dummies书中学到的. (10认同)

Mat*_*hen 46

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

如果你很好奇,这就是gcc 4.4.1给我的x86.两者都使用x86 JMP指令.

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

void for_infinite()
{
    for(;;)
    {
    puts("for");
    }
}
Run Code Online (Sandbox Code Playgroud)

汇编到(部分):

.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
Run Code Online (Sandbox Code Playgroud)

  • `for_infinite`更快; 'puts`少2个字符. (99认同)

Boa*_*ann 42

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

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

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

  • 感谢您的回答!我认为这实际上是第一个回答,它显示了一种**目标,即"for(;;)"更好. (9认同)
  • 我认为我不需要编写在C,C++,JavaScript,Java和C#中正确的代码.他们是不同的语言. (8认同)
  • @KeithThompson这不是关于在许多语言中编写正确的代码; 我认为这是为了避免不同背景的开发人员之间的误解. (6认同)
  • @sam:`while(1)`和`for(;;)`是C中无限循环的常用习惯用法.任何阅读C程序的人都很难理解其他代码可能会遇到问题.编写可以由不懂C的人轻松阅读的C代码是不值得的. (6认同)
  • @KeithThompson虽然C的一个称职的读者肯定应该熟悉这两个习语,但如果作者是一个多语言程序员,这也可能是有用的.在我上一份工作中,我每天都使用JS,ActionScript和PHP,并且统一编写代码的方式(这样做有意义)可以使编程更快,维护更容易. (6认同)
  • 这是切换到“ for”的一个很好的理由,因为这篇文章中的内容让我很烦。 (2认同)

Mic*_*urr 21

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

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

一个无限循环结构应该很容易被注意到或在代码中调用,我个人认为这种for (;;)风格比while (TRUE)或者好一点while (1).

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


rme*_*dor 17

我见过有些人喜欢它,因为他们有一个像这样的#define:

#define EVER ;;
Run Code Online (Sandbox Code Playgroud)

这允许他们写这个:

for (EVER)
{
    /* blah */
}
Run Code Online (Sandbox Code Playgroud)

  • 我也见过这个; 但这并不是一个很好的理由.作为维护者,您仍然需要检查宏定义以确定它是否符合您的期望,而原始代码足够清晰.RTOS VxWorks有一个宏`FOREVER`定义`for(;;)`,但这并不好.IMO宏不应该用于"发明"一种新语言. (24认同)
  • 有些人做有趣的事情,比如他们喜欢Pascal,他们说'#define BEGIN {`和`#define END}`.我甚至看过`#define DONKEYS_FLY(0)`所以他们可以说`如果DONKEYS_FLY ......`.谁说软件很无聊? (14认同)
  • 在加利福尼亚,我相信你必须#define for(;;)LIKE_FOREVER (11认同)
  • 实际上,某些语言中宏的目的是发明新的语法.但无论在C/C++中'for(EVER)'是多么令人发指. (7认同)

小智 16

那么(如果你的语言支持它):

start:
/* BLAH */
goto start;
Run Code Online (Sandbox Code Playgroud)

  • +1!它并没有改善`goto`的众多缺点,但是,如果你想要实现的算法来自流程图,这是最直接的翻译. (9认同)
  • 我个人对goto采取功利主义观点.没有猛禽.猛禽是人.人们开始使用goto制作意大利面条代码.此外,循环的组合输出看起来就像这样.计算机的指令集没有"for"或"while"的概念,只是"jump". (4认同)
  • 关于“goto”的真正好处是,您不必担心有人添加“break”来减少循环的无限性。(当然,除非你已经在另一个“while”或“for”循环中......) (2认同)

Jas*_*ams 12

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

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

  • 是的,不熟悉C或C++的人可能会发现STRING_SCAN_FORMATTED比sscanf更具可读性,但您没有看到任何人将#define STRING_SCAN_FORMATTED sscanf置于其代码的顶部. (9认同)
  • 这取决于你的语言.`for(;;)`是在C和C++中执行此操作的传统方法.`while(true)`似乎是C#和Java以及其他语言的惯例.你的旅费可能会改变. (6认同)
  • @despart:如果有人不熟悉C++来识别它的成语,那么他们需要远离我的代码库. (5认同)
  • 我认为这样做的惯用方法*对你的开发人员来说是最好的*.否则你真的需要更好的开发者. (4认同)
  • 我同意惯用的方式应该是最具可读性的.这就是为什么随着语言和实践的发展,惯用方法总是需要受到挑战和改变.可怕的K&R"惯用"编码风格需要多年才能被现代的,更具可读性的风格所取代,但它仍然存在. (4认同)
  • 但是,对C或C++不熟悉的人会更容易阅读(真实),熟悉他们的人也会理解它,因此更具可读性. (3认同)

Jam*_*eod 11

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

  • 是的,我认为有些编译器警告`while(true)`的原因与`if(true)`相同. (3认同)

Mic*_*ael 11

while(true)
Run Code Online (Sandbox Code Playgroud)

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

for(;;)
Run Code Online (Sandbox Code Playgroud)

是优选的.

  • 您使用的是哪个版本的视觉工作室?在2008年,即使在警告级别4,我也不会收到此警告. (7认同)
  • Visual Studio 2005,SP1 (2认同)

小智 11

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

int x = 0;

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

    printf("%d", x);
}
Run Code Online (Sandbox Code Playgroud)

如果您在调试模式下构建它(没有任何优化(/ 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)  
Run Code Online (Sandbox Code Playgroud)

但是,如果在Release模式下构建代码(默认最大化速度(/ 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)  
Run Code Online (Sandbox Code Playgroud)

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


Mar*_*hon 9

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

我发现如果更快输入"while(TRUE)".

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

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

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

  • s /个人偏好/个人习惯/ (6认同)
  • 我认为OP指的是运行速度,而不是打字速度. (3认同)

Mik*_*vey 6

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

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

你应该关心吗?

只有你在循环中做的事几乎没有,这几乎不是这样的.

我的观点是,存在微优化和宏优化.微观优化就像"理发减肥".

  • @Dennis Zickefoose:如果`i`是类的实例而不是内置的,并且编译器不应用简单的优化,那么`++ i`和`i ++`之间的区别可能很大.建议是养成一种习惯,以便它在重要时不会让你失望. (7认同)
  • 关于`++ i` vs`i ++`的事情是它不会花费你任何东西来进行"优化".是的,在大多数情况下它完全没有区别,但它们同样容易打字,所以为什么不喜欢默认情况下最有效的?我想这同样适用.如果一个*比另一个快一点,为什么*不*去寻找更快的?这样做我们会失去什么?两者都相当容易阅读和输入. (4认同)
  • 你经常看到人们更喜欢"++ i"而不是"i ++"吗? (3认同)
  • @Dennis Zickefoose:你是对的.我在SO上看到了很多,Clifford的评论是正确的.另外,我不会在SO上看到很多东西,那就是如何进行宏优化,比如43倍的加速:http://stackoverflow.com/questions/926266/performance-optimization-策略-的最后手段/ 927773#927773.所以我想知道我们的优先事项. (2认同)
  • @Mike:是的,但那是苹果与橘子的比较.理发需要实际时间,甚至可能是金钱.我同意这是一个微观优化,它并不重要.但它也不会给我们带来任何损失.如果我可以选择向左或向右,距离是相同的,地形是相同的,*一切*是相同的,除了左边的路径有一些微小的边缘效益,为什么不离开呢?你是对的,这不是一个令人印象深刻的论点.但是当成本几乎为零时,我认为没有理由选择不太理想的路线. (2认同)

Cli*_*ord 5

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

不过我建议你更喜欢for(;;)以下原因:

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

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

  • 有无限的while循环如许多可能的变型while(1),while(true),while(1==1)等; 因此for(;;)可能会带来更大的一致性.


Arm*_*ada 5

for(;;Sleep(50))
{
    // Lots of code
}
Run Code Online (Sandbox Code Playgroud)

比以下更清楚:

while(true)
{
    // Lots of code
    Sleep(50);
}
Run Code Online (Sandbox Code Playgroud)

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

  • @ ST3 - 是的,你是对的.我的代码很糟糕.下次我做一个无限循环时我应该更加努力. (11认同)
  • 在这样的for循环中调用像sleep这样的函数没有什么不干净的 (2认同)