При реализации бесконечного цикла, есть ли разница в использовании while (1) против for (;;) против goto (в C)? - PullRequest
28 голосов
/ 18 февраля 2010

При реализации бесконечного цикла есть ли разница в использовании while(1) против for(;;) против goto?

Спасибо, Chenz

Ответы [ 8 ]

51 голосов
/ 18 февраля 2010

Они эквивалентны, даже если вы выключите оптимизатор.

Пример:

#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
7 голосов
/ 18 февраля 2010

Я только что сравнил неоптимизированный ассемблерный вывод 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% случаев.

4 голосов
/ 18 февраля 2010

while(1) и for(;;) в точности эквивалентны, и оба являются хорошо понятными идиомами для кодирования бесконечных циклов.

Я бы избегал использования goto: чтобы выйти из бесконечного цикла или перейти к следующей итерации, используйте break и continue.

4 голосов
/ 18 февраля 2010

В генерируемой сборке почти нет разницы. Это скорее стилистическая проблема:

Перейти - просто оооо: переход назад, без явного бесконечного блока

while (1) - лучше, хотя требуется условие "фиктивная", и вы будете часто предупреждены компилятором (уровень предупреждения 4) или инструментом статического анализа

for (;;) может быть не самым красивым, но imho подходит лучше всего, потому что эта конструкция не может иметь никакого другого значения (по сравнению с while). Но некоторые другие предпочитают while (1) по «той же» причине ...

3 голосов
/ 18 февраля 2010

Хотя нет существенной разницы, как упоминалось в других публикациях, общая причина использования for (;;) вместо while (1) заключается в том, что инструменты статического анализа (и некоторые компиляторы с определенными уровнями предупреждений) часто жалуются на цикл while. 1003 *

Goto немного неприятен, но должен выдавать тот же код, что и остальные. Лично я придерживаюсь for (;;) (чтобы Линт был доволен), но у меня нет проблем с while (1).

3 голосов
/ 18 февраля 2010

Отсутствует. Используйте то, что наиболее читабельно для вас

2 голосов
/ 18 февраля 2010

В C true реализовано следующим образом (в зависимости от компилятора)

#define TRUE 1

или

#define TRUE (-1)

И ложь реализована как

#define FALSE 0

, поэтому while (1) эквивалентно while (true), поскольку 0 считается ложным.

while (1) == for (; ;), поскольку нет условий остановки.

что переводится ассемблеру как

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

, поэтому, если код ассемблера не имеет инструкции ret или exit, он считается бесконечным циклом.

0 голосов
/ 18 февраля 2010

Из того, что я помню о моих "разборочных годах", это не будет иметь большого значения (компиляторы умны достаточно). Больше об эстетике IMO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...