for (;;) {
//Something to be done repeatedly
}
Często widziałem takie rzeczy, ale myślę, że jest to raczej dziwne… Czy nie byłoby o wiele jaśniej powiedzieć while(true)
, czy coś w tym stylu?
Zgaduję, że (co jest powodem, dla którego wielu programistów ucieka się do tajemniczego kodu) jest to niewielki margines szybciej?
Dlaczego i czy naprawdę warto? Jeśli tak, dlaczego nie zdefiniować tego w ten sposób:
#define while(true) for(;;)
Zobacz także: Co jest szybsze: while (1) czy while (2)?
c++
c
optimization
readability
infinite-loop
Chris Cooper
źródło
źródło
TRUE
???TRUE
ma wspólnego z C? Standardowe makro dla prawdziwego wyniku boolen w C99 jest nadaltrue
. Skąd się wziąłTRUE
?#define EVER ;;
zostało jednak użyte w IOCCC .. :)#define while(TRUE)
deklarowania makra, które przyjmuje jeden argument,TRUE
który nigdy nie jest używany, a zatem zamienia każdą pojedynczą pętlę while w programie w nieskończoną pętlę?TRUE
pochodzi z plików nagłówkowych powiązanych z Windows API. Nie jest w żaden sposób powiązany z VS 6.0. I, jak powiedziałem wcześniej, nie ma to nic wspólnego ani z C, ani z C ++. W C ++ „prawdziwy” literał to po prostutrue
(również w VS 6.0), w C89 / 90 w ogóle czegoś takiego nie ma, aw C99 jest to makrotrue
. Dotyczy to wszystkich kompilatorów C / C ++.Odpowiedzi:
źródło
wolę
for(;;)
z dwóch powodów.Po pierwsze, niektóre kompilatory wyświetlają ostrzeżenia dotyczące
while(true)
(coś w rodzaju „warunek pętli jest stały”). Unikanie ostrzeżeń jest zawsze dobrą rzeczą.Po drugie, myślę, że
for(;;)
jest jaśniejszy i bardziej wymowny. Chcę nieskończonej pętli. To dosłownie ma ma warunku, nie zależy od niczego. Chcę tylko, żeby trwało to wiecznie, dopóki nie zrobię czegoś, aby się z tego wyrwać.Podczas gdy z
while(true)
cóż, co ma wspólnego z czymkolwiek? Nie interesuje mnie pętla, dopóki prawda nie stanie się fałszem, co dosłownie mówi ta forma (pętla, gdy prawda jest prawdziwa). Chcę tylko zapętlić.I nie, nie ma absolutnie żadnej różnicy w wydajności.
źródło
for(;;)
, będzie to oczywiście dziwnie wyglądać. Ale radziłbym spróbować się do tego przyzwyczaić, ponieważ jest to powszechny idiom i znowu się z nim spotkasz. ;)for(;condition;)
. To właśnie pętli while jest za . Ale tak jak powiedziałem, w przypadku nieskończonej pętli nie chcę, aby kompilator porównywał jakiekolwiek warunki. Naiwnie, zwhile
pętlą, musiałby przetestowaćtrue
każdą iterację (oczywiście nawet najgłupszy kompilator tego nie zrobiłby, ale przeszkadza mi ta zasada. Wydaje mi się, że zbytnio określam kod), podczas gdy z afor(;;)
you dosłownie mówisz „nie ma warunku do sprawdzenia. Po prostu zapętlaj”. Uważam, że jest to najbliższy odpowiednik twojego wyimaginowanegoloop {...}
while(true)
wyświetla ostrzeżenie.Osobiście używam,
for (;;)
ponieważ nie ma w nim żadnych liczb, to tylko słowo kluczowe. Wolę gowhile (true)
,while (1)
,while (42)
,while (!0)
etc etc.źródło
true
nie jest bardziej magiczną liczbą niżfor
magiczne słowo kluczowe lub którefor(;;)
używa implikowanej magicznej nieskończoności. (while (42)
jest rzeczywiście obrzydliwością.)for(;;)
jest analizowany szybciej niż inne#define LIFE 42
while (LIFE)
:)while(true)
nie zawiera też żadnej liczby. a dla (;;) nie jest słowem kluczowymZ powodu Dennisa Ritchiego
Zacząłem używać,
for (;;)
ponieważ tak robi to Dennis Ritchie w K&R, a ucząc się nowego języka, zawsze staram się naśladować sprytnych facetów.To jest idiomatyczne C / C ++. Prawdopodobnie lepiej na dłuższą metę przyzwyczaić się do tego, jeśli planujesz dużo robić w przestrzeni C / C ++.
Twój
#define
nie zadziała, ponieważ rzecz # define'd musi wyglądać jak identyfikator C.Wszystkie nowoczesne kompilatory będą generować ten sam kod dla obu konstrukcji.
źródło
while(TRUE)
, podejrzewam, że programista jest nowicjuszem w C lub nauczył się C z książki For Dummies.Z pewnością nie jest szybszy w żadnym rozsądnym kompilatorze. Obaj zostaną zestawieni w bezwarunkowe skoki. Wersja for jest łatwiejsza do wpisania (jak powiedział Neil) i będzie zrozumiała, jeśli zrozumiesz składnię pętli.
Jeśli jesteście ciekawi, oto co daje mi gcc 4.4.1 dla x86. Oba używają instrukcji x86 JMP .
kompiluje się do (częściowo):
źródło
for_infinite
jest szybszy; 2 mniej znaków doputs
.Wolę,
for (;;)
ponieważ jest najbardziej spójny w różnych językach podobnych do C.W C ++
while (true)
jest w porządku, ale w C musisz zdefiniować nagłówektrue
, aleTRUE
jest to również powszechnie używane makro. Jeśli używaszwhile (1)
go poprawnie w C i C ++ oraz JavaScript, ale nie w Javie lub C #, które wymagają, aby warunek pętli był wartością logiczną, na przykładwhile (true)
lubwhile (1 == 1)
. W PHP w słowach kluczowych nie jest rozróżniana wielkość liter, ale język preferuje wielkie literyTRUE
.Jednak
for (;;)
we wszystkich tych językach jest zawsze całkowicie poprawne.źródło
for (;;)
jest lepszy.while (1)
ifor (;;)
są powszechnymi idiomami dla nieskończonych pętli w C. Każdy, kto czyta program w C i ma problemy ze zrozumieniem któregokolwiek z nich, prawdopodobnie będzie miał problem z resztą kodu. Nie warto pisać kodu w C, który może być łatwo odczytany przez kogoś, kto nie zna C.Osobiście wolę
for (;;)
idiom (który zostanie skompilowany do tego samego kodu cowhile (TRUE)
.Używanie
while (TRUE)
może być bardziej czytelne w pewnym sensie, zdecydowałem się użyćfor (;;)
idiomu, ponieważ się wyróżnia .Konstrukcja nieskończonej pętli powinna być łatwo zauważalna lub wywoływana w kodzie i osobiście uważam, że
for (;;)
styl robi to nieco lepiej niżwhile (TRUE)
lubwhile (1)
.Przypominam też, że niektóre kompilatory wyświetlają ostrzeżenia, gdy kontrolujące wyrażenie pętli while jest stałą. Nie wydaje mi się, żeby to się zdarzało zbyt często, ale wystarczy mi możliwość fałszywych ostrzeżeń, abym chciał tego uniknąć.
źródło
Widziałem, że niektórzy wolą to, ponieważ mają #define gdzieś w ten sposób:
Co pozwala im napisać to:
źródło
FOREVER
zdefiniowane makrofor(;;)
, ale to nie jest lepsze. Makra IMO nie powinny być używane do „wymyślania” nowego języka.#define BEGIN {
i#define END }
. Widziałem nawet,#define DONKEYS_FLY (0)
żeby mogli powiedziećif DONKEYS_FLY ...
. Kto powiedział, że oprogramowanie jest nudne?#define never while(0)
i#define always
A co z (jeśli twój język to obsługuje):
źródło
goto
to wielu wad, ale jeśli algorytm, który próbujesz zaimplementować, pochodzi z schematu blokowego, jest to najbardziej bezpośrednie tłumaczenie.goto
goto
jest to, że nie musisz się martwić, że ktoś doda a,break
aby Twoja pętla była mniej nieskończona. (chyba że jesteś już w innej pętliwhile
lubfor
oczywiście ...)Nie ma różnicy pod względem generowanego kodu maszynowego.
Jednak, aby przezwyciężyć ten trend, argumentowałbym, że forma while (TRUE) jest znacznie bardziej czytelna i intuicyjna niż for (;;), a czytelność i przejrzystość są znacznie ważniejszymi powodami dla wytycznych kodowania niż jakiekolwiek powody, dla których ja ' słyszałem o podejściu for (;;) (wolę oprzeć moje wytyczne dotyczące kodowania na solidnym uzasadnieniu i / lub dowodzie skuteczności).
źródło
for(;;)
jest tradycyjnym sposobem na zrobienie tego w C i C ++.while(true)
wydaje się być konwencją w C # i Javie i innych językach. Twój przebieg może się różnić.Nie tylko dobrze znany wzorzec, ale standardowy idiom w C (i C ++)
źródło
while (true)
tego samego powodu co dalejif (true)
.generuje ostrzeżenie w programie Visual Studio (stan jest stały). Większość miejsc, w których pracowałem, kompiluje kompilacje produkcyjne z ostrzeżeniami jako błędami. Więc
jest preferowany.
źródło
Oba powinny być takie same, jeśli kod jest zoptymalizowany przez kompilator. Aby wyjaśnić, co rozumiem przez optymalizację, oto przykładowy kod napisany w MSVC 10:
Jeśli zbudujesz go w trybie debugowania ( bez żadnej optymalizacji (/ Od) ), demontaż pokazuje wyraźną różnicę. Istnieją dodatkowe instrukcje dotyczące
true
stanu wewnątrzwhile
.Jeśli jednak zbudujesz swój kod w trybie wydania (z domyślną maksymalną prędkością (/ O2) ), otrzymasz te same dane wyjściowe dla obu. Obie pętle są zredukowane do jednej instrukcji skoku.
Niezależnie od tego, którego użyjesz, nie ma znaczenia, ponieważ przyzwoity kompilator z optymalizacją prędkości jest włączony.
źródło
To kwestia osobistych preferencji, który sposób jest szybszy. Osobiście jestem typem dotykowym i nigdy nie patrzę na klawiaturę, podczas programowania - potrafię wpisywać dotykowo wszystkie 104 klawisze na swojej klawiaturze.
Uważam, że szybciej wpisuję „while (TRUE)”.
Dodałem w myślach kilka pomiarów ruchu palca i zsumowałem je. „for (;;)” ma około 12 szerokości klawiszy ruchów do tyłu i do czwartego (między klawiszami home a klawiszami oraz między klawiszami home a klawiszem SHIFT), natomiast (TRUE) ma około 14 szerokości klawiszy ruchów wstecz i czwarty.
Jednak podczas pisania tego drugiego jestem znacznie mniej podatny na błędy. Myślę mentalnie słowami naraz, więc szybciej wpisuję rzeczy takie jak „nIndex” niż akronimy takie jak „nIdx”, ponieważ muszę w myślach przeliterować litery, zamiast wypowiadać je w myślach i pozwalać palcom na automatyczne pisanie -wpisz słowo (jak jazda na rowerze)
(Mój test porównawczy TypingTest.com = 136 WPM)
źródło
time head -10 >/dev/null
, wpisz co 10 razy i zmierz wyniki. Założę się, że będziesz szybszy,for(;;)
chyba że oszukasz. Byłem o około 14%.Wszystkie dobre odpowiedzi - zachowanie powinno być dokładnie takie samo.
JEDNAK - tylko przypuśćmy, że ZROBIŁO różnicę. Załóżmy, że jeden z nich otrzymał 3 dodatkowe instrukcje na iterację.
Czy powinno cię to obchodzić?
TYLKO jeśli to, co robisz wewnątrz pętli, jest prawie niczym , co prawie nigdy nie ma miejsca.
Chodzi mi o to, że jest mikro-optymalizacja i makro-optymalizacja. Mikro-optymalizacja jest jak „strzyżenie, aby schudnąć”.
źródło
++i
nadi++
?++i
ii++
może być potencjalnie znacząca, jeślii
jest to instancja klasy, a nie wbudowana, a kompilator nie stosuje trywialnej optymalizacji. Rada jest taka, aby nabrać nawyku, aby nie złapał Cię, gdy się liczy.++i
VSi++
jest to, że nic Cię nie kosztuje, aby dokonać „optymalizacji”. To prawda, w większości przypadków nie robi to żadnej różnicy, ale są równie łatwe do wpisania, więc dlaczego nie preferować potencjalnie najbardziej wydajnych domyślnie? Przypuszczam, że to samo dotyczy tutaj. Jeśli jeden był odrobinę szybszy od drugiego, dlaczego nie wybrać szybszego? Co stracilibyśmy, robiąc to? Oba są dość łatwe do odczytania i przepisania.Nie wyobrażam sobie, żeby wartościowy kompilator wygenerował inny kod. Nawet gdyby tak było, nie byłoby możliwości określenia, bez przetestowania konkretnego kompilatora, który jest bardziej wydajny.
Jednak sugeruję, abyś wolał
for(;;)
z następujących powodów:kilka kompilatorów, których użyłem, wygeneruje stałe ostrzeżenie o wyrażeniu while (true) z odpowiednimi ustawieniami poziomu ostrzeżenia.
w twoim przykładzie makro TRUE może nie być zdefiniowane zgodnie z oczekiwaniami
istnieje wiele możliwych wariantów w nieskończonej pętli while takie jak
while(1)
,while(true)
,while(1==1)
itp .; więcfor(;;)
prawdopodobnie spowoduje większą spójność.źródło
while(TRUE)
wartościowane jakowhile(0)
prawdopodobnie nie odniesie korzyścifor(;;)
.while(true)
powinno być preferowane w każdym przypadku. W C ++bool
jest zarezerwowane, aw C zdefiniowane w C stdbool.h (czyniąc go mniej bezpiecznym w C).for(;;)
usuwa wszelkie wątpliwości.Jest jaśniejsze niż:
Nie dotyczy to sytuacji, gdy nie używasz
Sleep()
.źródło
timerService.scheduleRepeating (50, [] () { /* lots of code */ });
Pętla „na zawsze” jest popularna w systemach wbudowanych jako pętla w tle. Niektórzy implementują to jako:
Czasami jest to realizowane jako:
A jeszcze inna implementacja to:
Kompilator optymalizujący powinien generować taki sam lub podobny kod asemblera dla tych fragmentów. Jedna ważna uwaga: czas wykonywania pętli nie jest dużym problemem, ponieważ te pętle trwają w nieskończoność, a sekcja przetwarzania zajmuje więcej czasu.
źródło
Zakładam, że (true) jest bardziej czytelne niż for (;;) - wygląda na to, że programista przeoczył coś w pętli for :)
źródło
Najważniejszym powodem używania „for (;;)” jest obawa przed używaniem „while (TRUE)” podczas programowania eksploracyjnego. Łatwiej jest kontrolować liczbę powtórzeń za pomocą „for”, a także łatwiej jest przekształcić pętlę „for” w nieskończoną.
Na przykład, jeśli konstruujesz funkcję rekurencyjną, możesz ograniczyć liczbę wywołań tej funkcji przed konwersją na nieskończoną pętlę.
Kiedy jestem pewien swojej funkcji, konwertuję ją na nieskończoną pętlę:
źródło