在实现无限循环时,使用 while(1) 与 for(;;) 与 goto (在 C 中)有区别吗?

Posted

技术标签:

【中文标题】在实现无限循环时,使用 while(1) 与 for(;;) 与 goto (在 C 中)有区别吗?【英文标题】:When implementing an infinite loop, is there a difference in using while(1) vs for(;;) vs goto (in C)? 【发布时间】:2011-01-18 07:59:33 【问题描述】:

在实现无限循环时,使用while(1) vs for(;;) vs goto 有区别吗?

谢谢, 陈兹

【问题讨论】:

我总是用while。我认为以这种方式构造的 for 循环没有任何意义。这只是个人喜好。 (在我看来,它缺少信息,而 while 循环(在我看来)更美观) 哪个无限循环比另一个快? 欺骗***.com/questions/2242646/… 使用for(;;) 允许您使用#define ever (;;) 并使用for ever ... ;) @KennyTM:这很有趣,但另一方面也具有误导性。通常一个“无限”循环实际上不会永远持续下去,而是直到它被“中断”。 【参考方案1】:

即使您关闭优化器,它们也是等效的。

例子:

#include <stdio.h>

extern void f(void) 
    while(1) 
        putchar(' ');
    


extern void g(void) 
    for(;;)
        putchar(' ');
    


extern void h(void) 
    z:
        putchar(' ');
    goto z;

使用 gcc -O0 编译会为所有 3 个函数提供等效的程序集:

 f:
 ;  [ EXTERNAL ]
 ;
 +00000 00000fb4 80402DE9             stmdb             sp!,r7,lr
 +00004 00000fb8 00708DE2             add               r7,sp,#0x0
 +00008 00000fbc 2000A0E3 loc_000008: mov               r0,#0x20
 +0000c 00000fc0 0A0000EB             bl                putchar (stub)
 +00010 00000fc4 FCFFFFEA             b                 loc_000008
 ;
 ;
 g:
 ;  [ EXTERNAL ]
 ;
 +00000 00000fc8 80402DE9             stmdb             sp!,r7,lr
 +00004 00000fcc 00708DE2             add               r7,sp,#0x0
 +00008 00000fd0 2000A0E3 loc_000008: mov               r0,#0x20
 +0000c 00000fd4 050000EB             bl                putchar (stub)
 +00010 00000fd8 FCFFFFEA             b                 loc_000008
 ;
 ;
 h:
 ;  [ EXTERNAL ]
 ;
 +00000 00000fdc 80402DE9             stmdb             sp!,r7,lr
 +00004 00000fe0 00708DE2             add               r7,sp,#0x0
 +00008 00000fe4 2000A0E3 loc_000008: mov               r0,#0x20
 +0000c 00000fe8 000000EB             bl                putchar (stub)
 +00010 00000fec FCFFFFEA             b                 loc_000008

【讨论】:

使用什么命令从目标文件生成这个特定的程序集输出? @bzeaman 有关如何为 g++ 和 clang++ 执行此操作以及如何添加 cmets 以便您知道要查看程序集的哪个部分的更多信息,请参阅我的回答 here...跨度> 【参考方案2】:

我只是比较了 gcc 的未优化的汇编输出:

# cat while.c 
int main() 
    while(1) ;
    return 0;


# cat forloop.c 
int main() 
    for (;;)  ;
    return 0;

制作汇编输出:

# gcc -S while.c 
# gcc -S forloop.c 

比较汇编文件:

# diff forloop.s while.s
1c1
<   .file   "forloop.c"
---
>   .file   "while.c"

如您所见,没有显着差异。这是输出

# cat while.s 
    .file   "while.c"
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
.L2:
    jmp .L2                    # this is the loop in both cases
    .size   main, .-main
    .ident  "GCC: (GNU) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

虽然这不是它们相同的技术证据,但我认为在 99.9% 的情况下是相同的。

【讨论】:

【参考方案3】:

生成的程序集几乎没有任何区别。这更像是一个风格问题:

Goto - 只是ooogly:向后跳转,没有明确的无限块

while(1) - 更好,不过需要“虚拟”条件,编译器(警告级别 4)或静态分析工具会经常警告您

for(;;) 可能不是最漂亮的,但恕我直言最适合,因为这个结构不能有任何其他含义(与 while 相比)。但是出于“相同”的原因,其他一些人更喜欢 while(1)...

【讨论】:

【参考方案4】:

虽然其他帖子中提到的没有显着差异,但使用for (;;) 而不是while (1) 的一个常见原因是静态分析工具(以及一些具有某些警告级别的编译器)经常抱怨while循环。

Goto 有点讨厌,但应该产生与其他代码相同的代码。就个人而言,我坚持使用 for (;;)(为了让 Lint 开心),但我对 while (1) 没有任何问题。

【讨论】:

【参考方案5】:

while(1)for(;;) 是完全等价的,并且都是众所周知的用于编写无限循环的惯用语。

我会避免使用goto:要从无限循环中中断或继续下一次迭代,请使用breakcontinue

【讨论】:

【参考方案6】:

没有。使用对您来说最易读的内容

【讨论】:

【参考方案7】:

在 C 中,true 实现如下(取决于编译器)

#define TRUE 1

#define TRUE (-1)

AND false 实现为

#define FALSE 0

所以while (1) 等价于while (true),因为0 被认为是假的。

while (1) == for (; ;) 因为没有停止条件。

它被翻译成汇编程序

:loop
  ...
  ...
  ...
  goto loop

因此,如果汇编代码没有retexit 指令,则视为无限循环。

【讨论】:

【参考方案8】:

根据我对“反汇编年”的回忆,它不会有太大的不同(编译器足够智能)。它更多的是关于美学 IMO。

【讨论】:

以上是关于在实现无限循环时,使用 while(1) 与 for(;;) 与 goto (在 C 中)有区别吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python3入门基础(05)循环语句

Python3入门基础(05)循环语句

无限循环与嵌套循环

在while循环中使用scanf进行无限循环

for和while与until的无限循环总结

无限while循环内的Sleep()函数