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
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
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
+1 dla kodu ARM :-) –
Jakie polecenie zostało użyte do wytworzenia tego konkretnego wyniku montażu z pliku obiektowego? – bzeaman
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.
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ę.
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.
Brak. Użyj tego, co jest dla Ciebie najbardziej czytelne:
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 ...
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)
.
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
.
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
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
Która nieskończona pętla jest szybsza od drugiej? – Anonym