可能重复:
for ( ; ; ) 或 while ( true ) - 哪个是正确的 C# 无限循环?
为什么选择 for (;;){} 而不是 while(1) ?
while(true)
、while(1)
和for(;;)
之间有什么区别?它们都是在类似C#和C/C++这样的语言中实现无限循环。但是其中一个比另一个更好吗?有什么建议吗?
可能重复:
for ( ; ; ) 或 while ( true ) - 哪个是正确的 C# 无限循环?
为什么选择 for (;;){} 而不是 while(1) ?
while(true)
、while(1)
和for(;;)
之间有什么区别?它们都是在类似C#和C/C++这样的语言中实现无限循环。但是其中一个比另一个更好吗?有什么建议吗?
程序编译后没有区别。
以下是三个C程序的摘录以及它们对应的生成汇编代码。
首先让我们尝试使用for
循环:
#include <stdio.h>
int main(){
for(;;)
printf("This is a loop\n");
return 0;
}
现在我们将尝试使用 while
循环:
#include <stdio.h>
int main(){
while(1)
printf("This is a loop\n");
return 0;
}
一个可怕的解决方案,goto
循环:
#include <stdio.h>
int main(){
alpha:
printf("This is a loop\n");
goto alpha;
return 0;
}
现在,如果我们检查生成的程序集,使用命令gcc -S loop.c
,它们都是这个样子的(我没有看到任何理由将它们单独发布,因为它们是相同的):
.file "loop.c"
.section .rodata
.LC0:
.string "This is a loop"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
.L2:
movl $.LC0, (%esp)
call puts
jmp .L2
.size main, .-main
.ident "GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"
.section .note.GNU-stack,"",@progbits
这部分是循环。它声明了一个标签,将字符串的地址复制到一个寄存器中,调用名为puts
的例程,然后跳回到标签:
.L2:
movl $.LC0, (%esp)
call puts
jmp .L2
因为它们都能做同样的事情,所以显然没有任何技术上的优势(至少如果你使用的是gcc
)。
然而,人们有自己的观点,可能出于各种原因更喜欢其中的一种。由于for(;;)
只有七个字符长,更容易输入(这是我的偏好)。另一方面,while(1)
给人一种测试条件总是评估为true
的错觉,某些人可能会发现更直观。只有极少数疯狂的人最喜欢goto
解决方案。
编辑:显然,一些编译器可能会对while(1)
产生警告,因为条件总是为真,但这样的警告可以很容易地禁用,并不影响生成的汇编代码。
gcc
,它不会发出这样的警告。也许我会在Visual Studio中试试。我使用生成的汇编代码来支持我的观点,即所有这些创建无限循环的方式都完全相同,因为我认为这样的声明应该有确凿的证据支持,而不是凭空捏造。 - ctype.hwhile (1)
,因为条件始终为真,而不会警告 for (;;)
,因为没有(显式的)条件。 - Keith Thompson