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

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

我已经看到了这种东西,但是我觉得这很奇怪……说实话,说这些话不是很清楚吗?

我猜(这是许多程序员求助于隐藏代码的原因),这是一个微小的利润更快?

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

 #define while(true) for(;;) 

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

  1. 这不是更快。
  2. 如果你真的在意,编译汇编输出为您的平台,并期待看到。
  3. 没关系。 这永远不重要。 写你的无限循环,但你喜欢。

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

一个是有些编译器在while(true)产生警告(类似“loop condition is constant”)。 避免警告总是一件好事。

另一个是我认为for(;;)更清晰,更有说服力。 我想要一个无限循环。 它从字面上看没有条件,它不依赖于任何东西。 我只是想让它继续下去,直到我做了一些事情来打破它。

while(true)while(true) ,什么是真的? 我对循环不感兴趣,直到真正变为假,这是这种forms从字面上说(循环而真实是真的)。 我只是想循环。

不,绝对没有性能差异。

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

任何理性的编译器肯定不会更快。 它们都将被编译成无条件的跳转。 for版本更易于input(如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 

由于丹尼斯·里奇

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

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

  • 你的#定义将不起作用,因为定义#的东西看起来像一个C标识符。

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

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

在C ++中, while (true)很好,但是在C中你依靠一个头来定义true ,而TRUE也是一个常用的macros。 如果使用while (1)则在C和C ++以及JavaScript(而不是Java或C#)中要求循环条件为布尔型(例如while (true)while (1 == 1) 。 在PHP中,关键字不区分大小写,但语言更喜欢大写字母TRUE

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

我个人比较喜欢for (;;)成语(它将编译成和while (TRUE)相同的代码。

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

一个无限循环的构造应该很容易被注意到,或者在代码中调用,我个人认为for (;;)样式比while (TRUE)while (1)要好一些。

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

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

 #define EVER ;; 

这允许他们写这个:

 for (EVER) { /* blah */ } 

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

 start: /* BLAH */ goto start; 
 while(true) 

用Visual Studio生成一个警告(条件是不变的)。 我工作的大多数地方都将编译生产版本与警告作为错误。 所以

 for(;;) 

是优选的。

不只是一个众所周知的模式,而是C(和C ++)中的一个标准习惯用法,

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

然而,为了逆转这个趋势,我认为while(TRUE)forms比(;;)更具可读性和直观性,而且可读性和清晰性是编码指南的重要原因,我已经听说了for(;;)的方法(我更喜欢把我的编码指导方针作为坚实的推理和/或我自己的有效性certificate)。

如果你的代码被编译器优化,两者应该是相同的。 为了解释我的意思是通过优化,这里是一个在MSVC 10编写的示例代码:

 int x = 0; while(true) // for(;;) { x +=1; printf("%d", x); } 

如果你在debugging模式下( 没有任何优化(/ Od) ),反汇编显示明显的差异。 里面有true情况的额外说明。

 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) )构build代码,则两者的输出相同。 两个循环都被简化为一个跳转指令。

 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) 

无论你使用什么样的编译器,速度优化都没有关系。

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

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

我精神上增加了一些手指运动测量值并将其累加起来。 “for(;;)”具有大约12个按键宽度的回退和第四次(在主键和键之间,以及主键和SHIFT键之间)“while(TRUE)”具有大约14个键宽第四。

但是,input后者时,我大大减less了错误。 我一次一个字地思考,所以比“nIdx”这样的缩写更容易input“nIndex”这样的东西,因为我必须在脑子里拼出字母,而不是在脑海里说出来,让我的手指自动types的字(如骑自行车)

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

所有的好答案 – 行为应该是完全一样的。

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

你应该在乎吗?

只有当你在循环内做的事情几乎没有 ,这几乎从来没有这样的情况。

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

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

比以下更清楚:

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

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

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

不过我build议你更喜欢for(;;) ,原因如下:

  • 我已经使用的许多编译器将会在while(true)时产生一个常量expression式警告,并带有适当的警告级别设置。

  • 在你的例子中,macrosTRUE可能没有按照你的预期定义

  • while(1)while(true)while(1==1)等等。 因此for(;;)可能会导致更大的一致性。

作为后台循环,“永久”循环在embedded式系统中非常stream行。 有些人把它实现为:

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

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

我假设while(true)比(;;)更具可读性 – 它看起来像程序员错过了for循环 🙂

谁在乎哪一个更快

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

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

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

当我确定我的function,然后将其转换为无限循环:

  for(;;) recursiveFunction(oneParam);