是“for(;;)”比“while(TRUE)”更快? 如果没有,为什么人们使用它?
for (;;) { //Something to be done repeatedly }
我已经看到了这种东西,但是我觉得这很奇怪……说实话,说这些话不是很清楚吗?
我猜(这是许多程序员求助于隐藏代码的原因),这是一个微小的利润更快?
为什么,这真的值得吗? 如果是这样,为什么不这样定义:
#define while(true) for(;;)
另见: 哪个更快:while(1)或while(2)?
- 这不是更快。
- 如果你真的在意,编译汇编输出为您的平台,并期待看到。
- 没关系。 这永远不重要。 写你的无限循环,但你喜欢。
我更喜欢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);