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

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

Спасибо, Ченз


person Crazy Chenz    schedule 18.02.2010    source источник
comment
Я всегда использую while. Я не вижу смысла в построенном таким образом цикле for. Это просто личное предпочтение. (Мне кажется, что отсутствует информация, а цикл while выглядит (для меня) более эстетичным)   -  person Tim    schedule 18.02.2010
comment
технически «1 в то время» - это условие, которое следует проверять на каждой итерации. Я действительно считаю, что все распространенные компиляторы достаточно умны, чтобы сделать прыжок из этого, а не из условного. Кроме того, все они равнозначны, за исключением стиля.   -  person falstro    schedule 18.02.2010
comment
Какой бесконечный цикл быстрее другого?   -  person Anonym    schedule 18.02.2010
comment
Дупите stackoverflow.com/questions/2242646/   -  person    schedule 18.02.2010
comment
Использование for(;;) позволяет вам #define ever (;;) и использовать for ever {...;)   -  person kennytm    schedule 18.02.2010
comment
+1 к KennyTM за этот замечательный #define   -  person tur1ng    schedule 18.02.2010
comment
придирка для @Neil: это полувек. Связанный вами вопрос касается while() и for() в целом. Этот вопрос касается бесконечных циклов.   -  person tomlogic    schedule 19.02.2010
comment
@KennyTM: Это смешно и, с другой стороны, вводит в заблуждение. Обычно бесконечный цикл длится не вечно, а до тех пор, пока он не будет прерван.   -  person chiccodoro    schedule 06.08.2010
comment
@chiccodoro #define indefinitely for(;;) indefinitely {}   -  person Andrew    schedule 27.05.2021


Ответы (8)


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

Пример:

#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
person kennytm    schedule 18.02.2010
comment
Какая команда использовалась для создания этого конкретного вывода сборки из объектного файла? - person bzeaman; 25.05.2016
comment
@bzeaman См. мой ответ здесь для получения дополнительной информации о том, как это сделать для g ++ и clang ++ и как добавлять комментарии, чтобы вы знать, на какую часть сборки смотреть ... - person Andrew; 27.05.2021

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

person Otto Allmendinger    schedule 18.02.2010

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

Goto - просто ooogly: прыжок назад, без явного бесконечного блока

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

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

person MaR    schedule 18.02.2010

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

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

person DrAl    schedule 18.02.2010

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

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

person Danilo Piazzalunga    schedule 18.02.2010

Никто. Используйте то, что вам удобнее всего

person MrValdez    schedule 18.02.2010

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

#define TRUE 1

or

#define TRUE (-1)

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

#define FALSE 0

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

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

который переводится на ассемблер как

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

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

person Buhake Sindi    schedule 18.02.2010

Судя по тому, что я вспоминал о "годах дизассемблирования", это не будет иметь большого значения (компиляторы достаточно умны). Это больше об эстетике ИМО.

person jldupont    schedule 18.02.2010