Jaka jest poprawna nieskończona pętla C #, for (;;) czy while (true)? [Zamknięte]

97

W moich czasach C / C ++ kodując „nieskończoną pętlę” jako

while (true)

czułem się bardziej naturalnie i wydawał mi się bardziej oczywisty niż

for (;;)

Spotkanie z PC-lint pod koniec lat 80-tych i późniejsze dyskusje na temat najlepszych praktyk wyrwały mnie z tego nawyku. Od tego czasu kodowałem pętle za forpomocą instrukcji sterującej. Dzisiaj, po raz pierwszy od dłuższego czasu, i być może moja pierwsza potrzeba nieskończonej pętli jako programista C #, mam taką samą sytuację. Czy jeden z nich jest poprawny, a drugi nie?

Bob Kaufman
źródło
5
Cztery identyczne odpowiedzi w mniej niż dwie minuty. Nie jest zły.
Jon B
5
Możesz uniknąć całego religijnego sporu, rozwijając swoją nieskończoną pętlę. Nie powinno to zająć dużo czasu ...
Stephen Darlington
7
Z ciekawości: dlaczego dla (;;) lepiej w C / C ++?
Vilx-
6
@Vilx, o ile pamiętam, stare kompilatory pisały bardziej wydajny kod z for (;;) niż while (1). Jestem pewien, że każdy przyzwoity nowoczesny kompilator wygeneruje prawie identyczny kod.
Stephen Darlington
4
Opierając się na komentarzach Stephena i Serhio: 1. while(true)wymaga warunku. for(;;)jest zatem lepszą reprezentacją nieskończonych pętli, które powtarzają się bezwarunkowo. 2. Stare, nieoptymalizujące kompilatory mogły faktycznie oceniać (true)pętlę. 3. C to minimalistyczny język z czasów teletypów, terminali 300 bodów i jednoznakowych nazw zmiennych. W środowisku, w którym liczy się każde naciśnięcie klawisza, for(;;)jest nieco krótszy niż while(true).
Richard Dingwall

Odpowiedzi:

124
while(true)
{

}

Jest zawsze tym, czego używałem i widziałem, jak inni używają pętli, która musi zostać przerwana ręcznie.

Adam Robinson
źródło
@RSolberg - to był rzut między dwiema podobnymi odpowiedziami oferowanymi w ciągu kilku sekund. Komentarz Adama doprowadził mnie do przyjęcia odpowiedzi opartej na zwyczajach, a nie konwencjach.
Bob Kaufman
1
while i for można złamać ręcznie
Allen Rice
2
Niestety ta odpowiedź nie odpowiada na pytanie. Prawidłowa odpowiedź to „oba są poprawne”.
David R Tribble,
2
@Loadmaster: To zależy od twojej definicji „poprawności” (a raczej jakiego rodzaju „poprawności” szukasz).
Adam Robinson
316

Kompilator C # przekształci oba

for(;;)
{
    // ...
}

i

while (true)
{
    // ...
}

w

{
    :label
    // ...
    goto label;
}

CIL dla obu jest taki sam. Większość ludzi uważa while(true)za łatwiejsze do odczytania i zrozumienia. for(;;)jest raczej tajemniczy.

Źródło:

Zepsułem trochę więcej z .NET Reflector i skompilowałem obie pętle z włączoną opcją „Optimize Code” w Visual Studio.

Obie pętle kompilują się do (z .NET Reflector):

Label_0000:
    goto Label_0000;

Wkrótce powinny zaatakować drapieżniki.

Pierre-Alain Vigeant
źródło
7
tak, tylko podwójnie zaznaczone, to cały ten sam kod IL, to powinna być zaakceptowana odpowiedź IMO :)
Allen Rice
63
+1 dla odniesienia xkcd
Ikke
4
Aby być pedantycznym, kompilator nie przekształca jednej formy instrukcji w drugą; raczej generuje identyczny kod dla obu instrukcji. Ten kod jest identyczny z gotoinstrukcją, przy okazji, co nie jest zaskoczeniem.
David R Tribble
1
a następnie goto jest tłumaczone na instrukcję jmp.
Marco M.
25
więc oczywiście goto LOOPjest poprawna nieskończona pętla C # :)
Dustin Getz,
61

Myślę, że to może być łatwiejsze do odczytania i jest zdecydowanie standardem do użycia w C #:

while(true)
{
   //Do My Loop Stuff
}
RSolberg
źródło
19
@voyager: 1 nie zastępuje „true” w C #.
Adam Robinson
17
Zauważ, że chociaż (1) jest nieprawidłowy C #: Stała 1 nie może zostać przekonwertowana na bool
Vinko Vrsalovic
4
while(1)nie jest prawidłowy w C #, ponieważ 1nie jest bool.
Pavel Minaev
47

Dysz, użyj:

while (!false)
{

}

LUB, jak zauważył jsight , możesz być podwójnie pewien:

while (!false && true)
{
}

Zanim ludzie na mnie krzyczą, to ten sam kod CIL, sprawdziłem :)

Allen Rice
źródło
Najlepsza odpowiedź w historii.
Larry
38

Aby powtórzyć kilka starych dowcipów:

  1. Nie używaj „ for (;;) {}” - to sprawia, że ​​stwierdzenie płacze.
  2. Chyba że, oczywiście, " #define EVER ;;".
Ben Blank
źródło
25
Albo #define ever (;;)który moim zdaniem jest bardziej czytelny. for ever {}
Chris Lutz,
1
Nie sądziłem, że możesz kiedykolwiek zrobić #define (;;) w C #, chociaż żart jest zabawny :)
Allen Rice
1
Ach. Programuję C na OS X. Nie wiedziałem, że preprocesor C # jest tak wykastrowany. Nie jestem nawet pewien, jak zacząłem czytać to pytanie, mam C # jako zignorowany tag ...
Chris Lutz
Preprocesor C # tak naprawdę nie jest preprocesorem, przynajmniej nie pod względem tego, co zapewniają C, C ++, PL / 1, a nawet asemblery makr. Pozwala tylko na włączanie i wyłączanie bloków kodu poprzez definiowanie / cofanie definicji symboli preprocesora.
David R Tribble
6
Albo jeszcze lepiej #define forever while(true)
:;
26

Jeśli chcesz przejść do starej szkoły, goto jest nadal obsługiwane w C #:

STARTOVER:  
    //Do something
    goto STARTOVER;

Aby uzyskać naprawdę nieskończoną pętlę, jest to polecenie główne. =)

JohnFx
źródło
9
xkcd.com/292
Callum Rogers
6
Głosowałem za tym z negatywnej oceny z powrotem do zera, ale tylko ze względu na jego wartość humorystyczną. Hej, i tak wszystkie pętle są kompilowane do instrukcji asemblera JMP, prawda?
David R Tribble
@Loadmaster: Dzięki, po prostu wyrzuciłem to jako kolejną opcję, niekoniecznie ją popierając.
JohnFx
2
@serhio: Jeszcze bardziej unikanie konstrukcji językowych wymykających się spod kontroli, ponieważ gdzieś coś czytasz. Żaden element językowy sam w sobie nie jest zły, można go używać tylko w zły sposób.
JohnFx,
2
@serhio: Widziałem obrzydliwości przeciwko naturze przy użyciu prawie każdego możliwego słowa kluczowego. To nie jest element języka, to programista. W każdym razie, jak zauważyłem w moim poprzednim komentarzu, nie popierałem tego. Dodałem to tylko dla kompletności i odrobiny humoru.
JohnFx,
21

Myślę, że while (true)jest trochę bardziej czytelny.

Marplesoft
źródło
10

W sytuacjach, w których potrzebowałem prawdziwej nieskończonej pętli, zawsze używałem

while(true) {...}

Wydaje się, że lepiej wyraża zamiar niż puste oświadczenie.

Michael Petrotta
źródło
10

Osobiście zawsze wolałem for(;;)właśnie dlatego, że nie ma warunku (w przeciwieństwie do tego, while (true)który ma zawsze prawdziwy). Jednak jest to naprawdę bardzo drobna kwestia stylu, o którą nie sądzę, aby była warta dyskusji. Nie widziałem jeszcze wytycznych w stylu C #, które nakazują lub zabraniają żadnego z tych podejść.

Pavel Minaev
źródło
nie warto w .NET, gdy kompilator przekształca (bad czytelny) dla bezwarunkowo w czasie z warunku.
serhio
3
@serhio: wyjaśnij proszę, co masz na myśli mówiąc „kompilator przekształca ... w a while”. Jeśli chodzi o programistę, kompilator przekształca kod wysokiego poziomu w IL. W IL nie ma while(lub for) pętli, są tylko etykiety i gotowe.
Pavel Minaev
1
zobacz odpowiedź Pierre-Alaina Vigeanta.
serhio
3
Jego odpowiedź może być lepiej sformułowana w taki sposób, że po prostu „kompilator generuje identyczny IL dla obu” (tak naprawdę nie wiesz, czy i kiedy przekształca cokolwiek na poziomie AST, aw każdym razie jest to szczegół implementacji). W każdym razie to nie wyjaśnia, dlaczego „nie warto tego robić w .NET”. To samo dotyczy C ++, Javy ...
Pavel Minaev,
6

Osobiście wolę for (;;)idiom (z punktu widzenia C / C ++). Chociaż zgadzam się, że while (true)jest w pewnym sensie bardziej czytelny (i to jest to, czego używałem, nawet w C / C ++), zwróciłem się do używania foridiomu, ponieważ:

  • to się wyróżnia

Myślę, że fakt, że pętla się nie kończy (w normalny sposób) jest warty „wywołania” i myślę, że for (;;)robi to trochę więcej.

Michael Burr
źródło
wreszcie, korzystając z tego, poczekamy trochę dłużej, zanim programy się skompilują (kompilacja transformacji z for => while)
zanim
3
@serhio: Niezupełnie. Nie przekształca go z forw while. Dla obu for (;;){}i while (true){}generuje nowy while(true){}kod. Zobacz tę odpowiedź .
wchargin
6

Zalecana jest oryginalna książka K&R dla C, z której C # może prześledzić swoje pochodzenie

for (;;) ...

dla nieskończonych pętli. Jest jednoznaczny, łatwy do odczytania i ma długą i szlachetną historię.

Dodatek (luty 2017 r.)

Oczywiście, jeśli uważasz, że ta zapętlona forma (lub jakakolwiek inna forma) jest zbyt tajemnicza, zawsze możesz po prostu dodać komentarz .

// Infinite loop
for (;;)
    ...

Lub:

for (;;)    // Loop forever
    ...
David R. Tribble
źródło
1
tak, ale to jest dla C, a nie dla C #.
serhio,
1
Działa w języku C #. Język C # został wyprowadzony (pośrednio) z C.
David R Tribble,
4
8 lat później zdecydowałeś zaktualizować swoją odpowiedź. Nicea
Metoniem
4

Powinno być while(true)nie while(1)tak while(1)jest nieprawidłowy w C #, tak;)

JRL
źródło
3

Alternatywnie można powiedzieć, że posiadanie nieskończonej pętli i tak jest zwykle złą praktyką, ponieważ wymaga warunku wyjścia, chyba że aplikacja naprawdę działa wiecznie. Jeśli jednak dotyczy to pocisku manewrującego, zaakceptuję wyraźny warunek wyjścia, który może nie być wymagany.

Chociaż podoba mi się ten:

for (float f = 16777216f; f < 16777217f; f++) { } 
Chris Chilvers
źródło
2
-1: nie każdy zrozumie twoją "nieskończoną pętlę" czytając kod, być może ktoś pomyśli, że to błąd i spróbuje go "naprawić" ...
serhio
W C # f < 16777217fjest zawsze false... więc to nigdy się nie zapętla.
NetMage,
2

Wolę nieco bardziej „piśmienny” kod. O wiele bardziej prawdopodobne jest, że zrobię coś takiego w praktyce:

bool shouldContinue = true;
while (shouldContinue)
{
    // ...

    shouldContinue = CheckSomething();
}
bobbymcr
źródło
1
Fuj. W rzeczywistości jest to do ... while()pętla w przebraniu. To zajęło mi tylko kilka sekund. Gdybyś napisał do ... while()pętlę, byłby natychmiast jasny. -1
sbi
po co marnować czas i zasoby na deklarowanie zmiennej, skoro można użyć while (true)? Moim zdaniem to nie ma sensu
waqasahmed
Uważam, że jest bardziej czytelny, zwłaszcza jeśli możesz dołączyć konkretną znaczącą flagę, np. „While (! This.canceled)”, aby wskazać, że anulowanie jest jedynym sposobem zatrzymania pętli, „while (! ProcessExited)”, aby wskazać pętlę powinien działać, dopóki proces zewnętrzny nie zniknie, itd. Jest wiele rzeczy, które prawdopodobnie „marnują zasoby”, a które są absolutnie właściwe w imię łatwości utrzymania lub czytelności. „while (prawda)” nie jest wcale takie złe, ale z mojego doświadczenia wynika, że ​​zazwyczaj istnieje lepszy sposób.
bobbymcr
1
+1. W większości przypadków prawdziwa nieskończona pętla nie jest tym, co faktycznie się dzieje i istnieje pewien stan, w którym chciałbyś się zatrzymać (np. Gdy drukarka się pali).
Lie Ryan
1
… W takim przypadku powinieneś użyć break.
Ry-
2

Nawet ja też mówię, że ten poniżej jest lepszy :)

while(true)
{

}
anishMarokey
źródło
1

Jeśli grasz w golfa kodowego, proponuję for(;;). Poza tym while(true)ma to samo znaczenie i wydaje się bardziej intuicyjny. W każdym razie większość programistów prawdopodobnie zrozumie obie odmiany, więc nie ma to większego znaczenia. Użyj tego, co najwygodniejsze.

sobellian
źródło
2
jeśli grasz w golfa, C # i tak jest niewłaściwym językiem.
SingleNegationElimination
1

Pod względem czytelności kodu while(true) w jakimkolwiek języku, który uważam, ma większy sens. Jeśli chodzi o to, jak widzi to komputer, w dzisiejszym społeczeństwie nie powinno być żadnej różnicy między bardzo wydajnymi kompilatorami i interpreterami.

Jeśli jest jakaś różnica w wydajności, jestem pewien, że tłumaczenie na MSIL zostanie zoptymalizowane. Możesz to sprawdzić, gdybyś naprawdę chciał.

Chris
źródło
1

Jedynym powodem, dla którego mógłbym powiedzieć, for(;;)są ograniczenia CodeDom (podczas gdy pętli nie można deklarować za pomocą CodeDom, a pętle for są postrzegane jako bardziej ogólna forma jako pętla iteracyjna).

Jest to dość luźny powód, aby wybrać ten inny niż fakt, że forimplementacja pętli może być używana zarówno dla normalnego kodu, jak i kodu wygenerowanego przez CodeDom. Oznacza to, że może być bardziej standardowy.

Uwaga: możesz użyć fragmentów kodu, aby utworzyć whilepętlę, ale cała pętla musiałaby być fragmentem ...

Mark Synowiec
źródło
1

Oba pełnią tę samą funkcję, ale ludzie generalnie wolą while(true). To łatwe do odczytania i zrozumienia ...

abhinav
źródło
0

Każde wyrażenie, które zawsze zwraca wartość true, powinno być OK dla pętli while.

Przykład:

1==1 //Just an example for the text stated before 
true
Jerzy
źródło
Dlaczego miałbyś kiedykolwiek zmusić go do wykonania porównania takiego jak 1 = 1, skoro prawda działa równie dobrze? Używanie obliczonego wyrażenia wydaje się równie głupie, jak definiowanie stałej, takiej jak NUMBER_OF_ARMS = 598-3596;
JohnFx
To przykład odpowiedzi podanej przed kodem :)
George