2010-02-18 12 views
20

Podczas wdrażania nieskończonej pętli, czy istnieje różnica w używaniu while(1) vs for(;;) vs goto?Podczas implementacji nieskończonej pętli, czy istnieje różnica w użyciu while (1) vs for (;;) vs goto (w C)?

Dzięki, chenz

+1

Zawsze używam, gdy. Nie widzę sensu w pętli for skonstruowanej w taki sposób. To tylko osobiste preferencje. (Wydaje mi się, że brakuje informacji, podczas gdy pętla while wygląda (dla mnie) bardziej estetycznie) – Tim

+0

technicznie, 1 na chwilę jest warunkiem, który powinien być testowany przy każdej iteracji. Sądzę, że wszystkie popularne kompilatory są na tyle sprytne, aby wyskoczyć z tego, a nie warunkowego. Poza tym wszystkie są równoważne, z wyjątkiem stylu. – falstro

+3

Która nieskończona pętla jest szybsza od drugiej? – Anonym

Odpowiedz

44

Są one równoważne, nawet po wyłączeniu optymalizatora.

przykład:

#include <stdio.h> 

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

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

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

podczas kompilacji gcc -O0 daje równoważne zespół dla 3 funkcje:

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 
+8

+1 dla kodu ARM :-) –

+0

Jakie polecenie zostało użyte do wytworzenia tego konkretnego wyniku montażu z pliku obiektowego? – bzeaman

0

Z tego co pamiętam z moich „demontażu lat”, to nie będzie dużo różnicę (kompilatory są mądry wystarczy). Chodzi bardziej o estetykę IMO.

2

W C true jest realizowany w następujący sposób (w zależności od kompilatora)

#define TRUE 1 

lub

#define TRUE (-1) 

i fałszywie jest wykonany jako

#define FALSE 0 

tak while (1) odpowiada while (true) ponieważ 0 jest uważane za fałszywe.

the while (1) == for (; ;) ponieważ nie ma warunków zatrzymania.

które są tłumaczone na asemblerze jako

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

więc jeśli kod asemblera nie posiada instrukcji ret lub exit, to uważa się za nieskończoną pętlę.

6

Właśnie porównano niezoptymalizowanych wyjście asemblera gcc:

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

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

Dodać assembler wyjście:

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

Porównaj pliki asemblera:

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

Jak widać nie ma znaczących różnic. Oto wynik

# 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 

Choć nie jest to dowód techniczny że są one takie same, powiedziałbym, że jest w 99,9% przypadków.

3

Brak. Użyj tego, co jest dla Ciebie najbardziej czytelne:

4

Nie ma prawie żadnej różnicy w generowanym złożeniu.To więcej o stylistycznej wydania:

Goto - tylko ooogly: skacze do tyłu, bez wyraźnej nieskończoną blok

while (1) - lepiej, wymaga „manekin” stan choć i będziesz często ostrzeżony przez kompilator (poziom ostrzegawczy 4) lub statycznego narzędzia do analizy

for (;;) może nie być najładniejsza, ale imho pasuje najlepiej, ponieważ konstrukcja ta nie może mieć żadnego innego znaczenia (w porównaniu do czasu). Ale niektórzy ludzie wolą, gdy (1) z tego samego powodu ...

2

Chociaż nie ma znaczących różnic, jak wspomniano w innych postach, częstym powodem używania for (;;) zamiast while (1) jest to, że narzędzia do analizy statycznej (i niektóre kompilatory z pewnymi poziomami ostrzeżeń) często narzekają na pętlę while.

Goto jest nieco nieprzyjemny, ale powinien generować ten sam kod, co pozostałe. Osobiście trzymam się for (;;) (aby zachować Lint szczęśliwy), ale nie mam problemu z while (1).

3

while(1) i for(;;) są dokładnie równoważne i oba są dobrze zrozumiałymi idiomami do kodowania nieskończonych pętli.

Unikałbym użycia goto: aby zerwać z nieskończonej pętli lub przejść do następnej iteracji, użyj break i continue.