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


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

我已经看到这种东西使用了很多,但是我觉得这很奇怪……说起来不是那么清晰while(true),或者类似的话吗?

我猜想(这是许多程序员诉诸密码的原因),这快一点点吗?

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

#define while(true) for(;;)

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


51
什么是TRUE???
AnT

20
@Steven Sudit:TRUE与C有什么关系?C99中真正布尔值结果的标准宏仍为true。哪里TRUE来的?
AnT

31
该宏不起作用,#define EVER ;;尽管已在IOCCC中使用.. :)

18
那个用于#define while(TRUE)声明一个带有一个称为TRUE永不使用的参数的宏的宏,是不是永远不会使用,因此将程序中的每个while循环都变成了无限循环吗?
AshleysBrain 2010年

9
@Steven Sudit:否。没有“ VS 6.0中的标准宏”。宏TRUE来自与Windows API关联的头文件。它与VS 6.0没有任何关系。而且,正如我之前所说,它与C或C ++无关。在C ++中,“ true”原义就是true(在VS 6.0中也是如此),在C89 / 90中根本没有这样的东西,在C99中是macro true。这适用于所有C / C ++编译器。
AnT

Answers:


262
  1. 不快。
  2. 如果您真的很在意,请使用平台的汇编输出进行编译,然后看看。
  3. 没关系 这无关紧要。根据需要编写无限循环。

227
直观地讲,优化无限循环提供了无限加速的潜力。那么,我们不要凭直觉进行编程。:-)
史蒂文·苏迪特

5
我想你是对的。我认为我陷入了关于小事的“宗教”辩论中。谢谢你摆脱我的良心。:D
克里斯·库珀

6
@Steven LOL,这很有趣,但是请考虑一下,您真正​​达到无限加速潜力的唯一情况是,循环永不中断且真正无限地运行,这很可能是错误,或者是预期的。无限等待,直到它达到那个潜力。
AaronLS 2010年

7
@克里斯。在生活中编程时,宗教辩论只值得您花时间去做真正重要的事情。这只是其中之一。如您所见,每个人都有写一个无限循环的小方法。自己挑选使自己最高兴的小事情,然后在重要的代码上运行分析器。:)
Ben Zotto

3
这确实很重要,因为某些平台上的某些早期编译器确实加载了常量并对其进行了条件跳转。在那些日子里,哪个硬件很重要。
peterchen

176

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

一种是某些编译器会在 while(true)(诸如“循环条件不变”之类的)。避免警告始终是一件好事。

另一个是我认为for(;;)更清楚,更能说明问题。我想要一个无限循环。它确实没有条件,这取决于什么。我只是希望它可以永远持续下去,直到我做出一些突破。

而与 while(true),那么,什么与什么真正相关?在true变为false之前,我对循环不感兴趣,这就是这种形式的字面意思(在true为true时循环)。我只想循环。

而且,绝对没有性能差异。


73
+1以避免警告。但是为了清楚起见,我发现比在这种情况下更清晰。我想这方面取决于个人喜好。
蒂姆(Tim)2010年

14
是的,偏好和习惯。如果您不习惯观看for(;;),显然会看起来很奇怪。但是我建议您尝试去适应它,因为它一个常见的习惯用法,您将再次遇到它。;)
jalf 2010年

7
杰夫(Jalf)关于它是惯用语的评论确实是这里的答案。它通常用于“无限循环”,只是因为它在C语言中编写“无限循环”的常用方法。没有成语的充分理由-它只是一种自我强化的约定。
caf 2010年

7
@Steve:我不明白为什么我会永远使用for(;condition;)。这是一个while循环是什么。但是就像我说的那样,对于无限循环,我真的不希望编译器比较任何条件。天真的,有一个while循环,它必须测试true每个迭代(很明显,即使最笨的编译器也不会这样做,但这是困扰我的原则。它使我过于夸大您的代码而感到震惊),而for(;;)您实际上是在说“没有条件可以测试。只需循环”。我发现它最接近的等同于你的想象loop {...}
jalf

32
如果while(true)发出警告,您的编译器会很烂。
艾伯特2010年

56

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


38
0、1和无穷大是可接受的幻数,将0和1扩展为false和true不会造成损失。 true不再是魔术数字,for而是魔术关键字或for(;;)使用隐含的魔术无穷大。(while (42)确实是可憎的。)

38
切线:我的一位CS教授说:“编程中只有三个数字:0、1和n。其他任何东西都称为幻数。”
Ben Zotto

21
while(42)是最酷的,相对于while(1)或while(true)或while(!0)不会产生不同的结果,并且具有哲学意义。for(;;)无论如何,我想它的解析速度比其他任何方法
都快

2
@ShinTakezou更好了#define LIFE 42 while (LIFE):)
mr5

1
好,while(true)也没有包含任何数字。并且for(;;)不是关键字
RiaD

49

由于丹尼斯·里奇

  • 我开始使用for (;;),是因为这就是Dennis Ritchie在K&R中所做的方式,当学习一种新语言时,我总是尝试模仿聪明的家伙。

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

  • #define将无法使用,因为#define必须看起来像C标识符。

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


10
是的,这就是您知道某人从K&R学习C的方式,这是应该学习的方式。每当我看到时while(TRUE),我都会怀疑程序员是C新手,还是从For Dummies一书中学习了C。
克里斯托弗·约翰逊

13
我听说那些新手也使用新功能的函数定义样式
贾斯丁

46

当然,在任何理智的编译器中都不会更快。它们都将被编译为无条件跳转。for版本更易于键入(如Neil所说),如果您了解for循环语法,它将很清楚。

如果您好奇,这是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

我怀疑即使在调试模式下它也会更快。
史蒂文·苏迪特

106
for_infinite是比较快的; 少2个字符puts
戴夫·贾维斯

43

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

在C ++ while (true)中可以,但是在C中,您依赖标头来定义true,但它TRUE也是一个常用的宏。如果使用while (1)它,则在C和C ++和JavaScript中是正确的,但在Java或C#中则不是正确的,而Java或C#要求循环条件为布尔值,例如while (true)while (1 == 1)。在PHP中,关键字不区分大小写,但语言首选大写TRUE

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


9
感谢您的回答!我认为这实际上是显示更好的客观方法的第一个答案for (;;)
克里斯·库珀

8
我认为我不需要编写在C,C ++,JavaScript,Java和C#中正确的代码。他们是不同的语言。
基思·汤普森

6
@KeithThompson并不是说在许多语言中编写正确的代码。我认为这是为了避免不同背景的开发人员之间的误解。
Mauro Sampietro 2014年

6
@sam:while (1)for (;;)都是C语言中无限循环的惯用语。任何阅读C程序的人如果不了解其中任何一个,都可能会遇到其余代码的麻烦。这是不值得写C代码,可以被人轻松读取,谁不知道C.
基思·汤普森

6
@KeithThompson虽然C的能干的读者肯定应该熟悉这两种习惯用法,但是如果作者是多语言程序员,这也可能很有用。在上一份工作中,我每天都使用JS,ActionScript和PHP进行工作,并且统一编写代码的方式(在这样做的意义上)可以使编程更快并且更容易维护。
Ionoclast Brigham 2014年

21

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

while (TRUE)从某种意义上讲,使用起来可能更具可读性,我决定使用这种for (;;)用语,因为它很突出

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

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


17

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

#define EVER ;;

他们可以这样写:

for (EVER)
{
    /* blah */
}

24
我也看到过 但这不是选择它的充分理由。作为维护者,您仍然必须检查宏定义,以确保它符合您的期望,而原始代码足够清晰。RTOS VxWorks FOREVER定义了一个宏for(;;),但这并不好。不应将IMO宏用于“发明”新语言。
克利福德,2010年

8
实际上,某些语言中宏的目的是发明新的语法。但是无论C / C ++中的“ for(EVER)”如何,都是令人发指的。
丹·奥尔森

15
有些人会做一些有趣的事情,例如,如果他们喜欢Pascal,他们会说#define BEGIN {#define END }。我什至看过了,#define DONKEYS_FLY (0)所以他们可以说if DONKEYS_FLY ...。谁说软件枯燥?
Mike Dunlavey 2010年

11
在加利福尼亚,我相信您必须为(;;)LIKE_FOREVER定义#;
Martin Beckett 2010年

1
我忍不住道:#define never while(0)#define always
alfC

16

怎么样(如果您的语言支持):

start:
/* BLAH */
goto start;

...应该在任何合理的编译器手中生成相同的输出。
本·佐托

9
+1!它并没有改善goto许多缺点,但是,如果您要实现的算法来自流程图,则这是最直接的翻译。
Edmund

4
我个人对goto持功利主义的观点。没有猛禽。猛禽是人。正是人们开始使用goto来制作意大利面条式代码。同样,循环的组合输出看起来也差不多。计算机指令集没有“ for”或“ while”的概念,只是“ jump”。
josaphatv

从未使用过goto
爱德华·卡拉克

真正有趣的goto是,您不必担心有人添加a break可以使循环的无限无限性。(除非你已经在另一个内部whilefor循环,当然...)

12

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

但是,为了逆势而上,我认为while(TRUE)格式比for(;;)更具可读性和直观性,而可读性和清晰性是编写准则的重要原因,比我提出的任何原因都重要。我曾经听说过for(;;)方法(我更愿意根据扎实的推理和/或有效性证明自己编写编码准则)。


6
那取决于你的语言。for(;;)是在C和C ++中执行此操作的传统方法。while(true)似乎是C#和Java等语言的惯例。你的旅费可能会改变。
Billy ONeal 2010年

9
是的,对C或C ++不太熟悉的人可能会发现STRING_SCAN_FORMATTED比sscanf更具可读性,但是您看不到有人将#define STRING_SCAN_FORMATTED sscanf放在其代码的顶部。
ta.speot.is 2010年

4
我想说,惯用的方法最好是让开发人员最容易理解。否则,您确实需要更好的开发人员。
jalf

5
@despart:如果某人对C ++不够熟悉,无法识别该成语,那么他们需要远离我的代码库。
Billy ONeal 2010年

4
我同意惯用的方式应该是最易读的。这就是为什么习惯语言总是需要随着语言和实践的发展而受到挑战和改变。可怕的K&R“惯用”编码样式用了几年时间才被现代,更易读的样式所取代,但是仍然发生了。
杰森·威廉姆斯


11
while(true)

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

for(;;)

是首选。


7
您正在使用哪个版本的Visual Studio?就2008年而言,即使在警告级别4时,我也不会收到此警告。
JörgenSigvardsson 2010年

11

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

int x = 0;

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

    printf("%d", x);
}

如果以Debug模式(没有任何优化(/ 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)  

对于启用了速度优化的体面的编译器,无论使用哪种方式都没有关系。


这实际上是一个很好的观点!如果不进行优化,那么即使是现代的编译器也会在几个指令上有所不同。

9

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

我发现键入“ while(TRUE)”是否更快。

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

但是,在键入后者时,我几乎不容易出错。我一次在思维中用语言思考,因此我发现键入“ nIndex”之类的单词要比诸如“ nIdx”之类的首字母缩写更快,因为我必须真正地在思维上拼写出字母,而不是在脑海中说出来并让我的手指自动输入单词(例如骑自行车)

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


3
我相信OP是指运行时速度,而不是输入速度。

我知道。只需覆盖该基础。
Mark Rejhon

7
s /个人喜好/个人习惯/
SamB

@SamB:对s ///进行投票表决。xD是的,尽管我建议这可能是由于运行时速度所致,但我不知道实际的答案。如果是这样,我会很高兴。
克里斯·库珀

运行time head -10 >/dev/null,每次键入10次,然后测量结果。我敢打赌你会更快for(;;)除非你作弊否则你。我大约减少了14%。
PSkocik

6

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

但是-假设它有所作为。假设其中之一在每次迭代中多了3条指令。

你应该在乎吗?

只有在循环内您几乎什么都做不到,几乎绝不会如此。

我的观点是,存在微观优化和宏观优化。微观优化就像“理发以减轻体重”。


3
的频率有多你看人家告诉喜欢++ii++
Dennis Zickefoose

7
@Dennis Zickefoose:之间的差别++ii++是否有可能成为显著i的,而不是一个类的实例内置和编译器不适用琐碎的优化。建议是养成一个习惯,这样它就不会在重要时吸引您。
克利福德,2010年

5
关于事情++iVS i++是,它不花费你任何东西使“优化”。没错,在大多数情况下,它绝对没有区别,但是它们同样易于键入,所以为什么不默认选择最有效的潜在方法呢?我想这里也一样。如果一个人一点点快于其他,为什么走的更快吗?我们这样做会失去什么?两者都很容易阅读和输入。
jalf

2
@丹尼斯Zickefoose:你是对的。我在SO上看到很多东西,而Clifford的评论是正确的。另外,在SO上我不到很多东西,那就是如何进行宏优化,例如43倍加速:stackoverflow.com/questions/926266/…。所以我想知道我们的优先事项。
Mike Dunlavey 2010年

2
@Mike:是的,但这是一个苹果与桔子的比较。理发需要花费实际时间,甚至可能要花钱。我同意这是一个微优化,因此并不重要。但这也不任何。如果我可以选择向左或向右走,并且距离是相同的,地形是相同的,一切都是一样的,除了左边的路径在边缘上有一些微观上的好处,为什么不走左边呢?没错,这不是令人印象深刻的论点。但是,当成本从零开始时,我认为没有理由偏向于最优路线。
jalf

5

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

但是,我建议您首选for(;;)以下原因:

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

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

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


TRUE可能不是#define TRUE 1,但while(TRUE)评估为的任何代码库while(0)都不太可能受益于for(;;)
贾斯汀

@Justin:我同意,这确实是不正确的,它不是三个参数中最强的,但是Bjarne Stoustrup使用类似的参数来避免C ++中的NULL宏。while(true)在任何情况下都应该是首选。在C ++中bool是保留的,而在C中则由C stdbool.h定义(使其在C中不太安全)。for(;;)消除所有疑问。
克利福德

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

比以下内容更清晰:

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

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


1
这是该死的错误代码,应该使用计时器而不是睡眠,所以这是一个不好的例子
ST3 2014年

12
@ ST3-是的,您是对的。我的代码太糟糕了。下次创建无限循环时,我应该更加努力。
舰队2014年

1
@Frammo-取决于您的操作系统,但通常类似于timerService.scheduleRepeating (50, [] () { /* lots of code */ });
Periata Breatta

2
没有什么干净的有关调用一样的睡眠内部的功能一样,环
格雷格

1
OMG,timerService.scheduleRepeating(50,[](){})太容易键入和理解,然后进入sleep(50)。
酷标枪

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 */);

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


8
如果编译器为此生成了不同的代码,那么该放弃该编译器,并从最近的二十年中获得一个。
GManNickG 2010年

5
“执行时间为循环也不是什么大问题,因为这些环路上永远继续下去” -听起来那么我错了..
Blindy

3
@Blindy-因为这是错误的,所以需要关注的是运行时在处理循环逻辑上花费的部分,或者每单位有用工作的循环逻辑量,而循环是无限的,这都不起作用
Ben Voigt

3

我假设while(true)比for(;;)更易读- 看起来程序员在for循环中遗漏了一些东西 :)


我在乎速度。特别是如果有优化将无限次影响我的代码。
科瓦尔斯基

2

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

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

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

当我确定自己的功能后,便将其转换为无限循环:

    for(;;) recursiveFunction(oneParam);

3
第一个循环存在语法错误(缺少分号)。
詹斯(Jens)

3
哈!从而展示了for(;;;;)的缺点
安德鲁(Andrew
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.