Czy powinienem zwrócić EXIT_SUCCESS czy 0 z main ()?

124

To proste pytanie, ale wciąż widzę sprzeczne odpowiedzi: czy główna procedura programu C ++ powinna powrócić, 0czy EXIT_SUCCESS?

#include <cstdlib>
int main(){return EXIT_SUCCESS;}

lub

int main(){return 0;}

Czy są dokładnie tym samym? Powinien EXIT_SUCCESSbyć używany tylko z exit()?

Pomyślałem, EXIT_SUCCESSże będzie to lepsza opcja, ponieważ inne oprogramowanie może chcieć uznać zero za awarię, ale słyszałem również, że jeśli wrócisz 0, kompilator i tak jest w stanie zmienić to na inną wartość.

Trevor Hickey
źródło
Czy to odpowiada na twoje pytanie? stackoverflow.com/questions/1188335/…
Blastfurnace
2
Ta odpowiedź dotycząca C90 parafrazuje standard - 0i EXIT_SUCCESSobie są interpretowane jako sukces.
ta.speot.is
Odpowiem tutaj, ponieważ czuję, że ktoś inny będzie to czytał w przyszłości. Zasadniczo istnieje wiele paradygmatów na temat tego, jak wygląda „prawidłowe C”. Niektóre paradygmaty wolą używać literałów zamiast makr, na przykład zamiast przekazywać NULL jako argument, mogą przekazać (const char *) 0, aby wskazać, że nie jest to tylko wartość null, ale jeśli nie jest null, powinno to być stały wskaźnik znaków. Inne paradygmaty wolą być agnostykami typu i używając typów makr, mogą uniknąć konieczności zmiany ich bazy kodu, gdy coś radykalnie się zmieni. Na przykład wiele -
Dmitry
@Dmitry <continued> Definicje typów Windows API nie są poprawne na nowszych platformach, ale ponieważ były to makra, mieli łatwy sposób zmiany wszystkich typów na te, które działają, ponownie definiując makro, a wiele z tych typów jest po prostu skalowanych z definicji (np. int jest różny na różnych platformach). Podsumowując, użyj rzeczy takich jak EXIT_SUCCESS, jeśli kod powrotu ma znaczenie i może ulec zmianie w przyszłości, w przeciwnym razie zwrócenie 0 może wydawać się magiczną liczbą, ale nadal jest to całkowicie poprawna standardowa konwencja. kod błędu dotyczy głównie programów do przesyłania wyników z jednego do drugiego, -
Dmitry
@Dmitry <continued> używanie kodów błędów do debugowania twojego programu jest trochę słabe, ponieważ jeśli zwraca 0, jest to dość bezużyteczna informacja, z wyjątkiem niektórych przypadków, gdy w programie występują niewywołane nieobsłużone błędy, które mogą spowodować ciche uszkodzenie programu, a potrzebujesz aby sprawdzić, czy zwróciło normalnie (0) lub wystąpił cichy błąd. Zwrot liczby jest bardziej przydatny przy przepuszczaniu 0..255 z jednego programu do drugiego na podstawie ich danych wejściowych, w przeciwnym razie nie ma powodu, aby o tym myśleć: albo zwróć 0, albo użyj prekompilowanego main, który wstawia void wywołanie "init", aby nie wizualnie irytuje cię bezużytecznym powrotem.
Dmitry

Odpowiedzi:

151

EXIT_FAILURE, albo w instrukcji return w, mainalbo jako argument do exit(), jest jedynym przenośnym sposobem wskazania błędu w programie w języku C lub C ++. exit(1)może faktycznie sygnalizować pomyślne zakończenie na przykład w VMS.

Jeśli zamierzasz używać, EXIT_FAILUREgdy program zawiedzie, równie dobrze możesz użyć, EXIT_SUCCESSgdy się powiedzie, tylko ze względu na symetrię.

Z drugiej strony, jeśli program nigdy nie sygnalizuje awarii, możesz użyć opcji 0lub EXIT_SUCCESS. Oba są gwarantowane przez standard, aby zasygnalizować pomyślne ukończenie. (Jest prawie niemożliwe, aby EXIT_SUCCESSmieć wartość inną niż 0, ale jest równa 0 w każdej implementacji, o której słyszałem).

Używanie 0ma niewielką zaletę, której nie potrzebujesz #include <stdlib.h>w C lub #include <cstdlib>C ++ (jeśli używasz returninstrukcji zamiast wywoływać exit()) - ale w przypadku programu o dowolnym znaczącym rozmiarze będziesz dołączać stdlib bezpośrednio lub pośrednio tak czy siak.

Jeśli o to chodzi, w C, począwszy od standardu 1999, i we wszystkich wersjach C ++, dotarcie do końca i main()tak jest niejawne return 0;, więc może nie być konieczne użycie jednej z nich 0lub EXIT_SUCCESSjawnie. (Ale przynajmniej w C uważam, że wyraźniejszy return 0;jest lepszy styl).

(Ktoś poprosił o OpenVMS. Nie używałem go od dłuższego czasu, ale o ile pamiętam nieparzyste wartości stanu na ogół oznaczają sukces podczas gdy wartości nawet oznaczać awarię. Realizacja C odwzorowuje 0się 1tak, że return 0;wskazuje na pomyślne zakończenie. Inne wartości są przekazywane niezmienione , więc return 1;również wskazuje pomyślne zakończenie. EXIT_FAILUREmiałby wartość parzystą różną od zera).

Keith Thompson
źródło
@KeithThompson czy mógłbyś wyjaśnić swoją odpowiedź w odniesieniu do VMS (OpenVMS?). Nie jest jasne, jaki jest związek EXIT_SUCCESS / EXIT_FAILURE z 0 i 1. Zamiast tego wyjaśniłbym wartości nieparzyste / parzyste.
malat
@malat: Czy faktycznie używasz VMS?
Keith Thompson,
nie, nigdy go nie używałem. Szukałem odpowiedzi kanonicznej, ponieważ wikipedia użyła innego sformułowania .
malat
1
@Rhymoid: Jest to określone przez C, a nie POSIX.
Keith Thompson
1
@DeanP: 0i EXIT_SUCCESSnie gwarantujemy, że będą miały tę samą wartość (wspomniałem o tym w mojej odpowiedzi), ale oba oznaczają pomyślne zakończenie. EXIT_SUCCESSjest stylistycznie lepszy, jeśli również używasz EXIT_FAILURE, ale exit(0)jest w porządku.
Keith Thompson,
25

Nie ważne. Obie są takie same.

C ++ Standardowe cytaty:

Jeśli wartość statusu wynosi zero lub EXIT_SUCCESS, zwracana jest zdefiniowana w implementacji postać pomyślnego zakończenia statusu.

Alok Save
źródło
12
Nie ma to znaczenia dla kompilatora, ale może mieć znaczenie ze względu na styl.
celtschk
2
@celtschk: Kwestia stylu opiera się na percepcji, czyli niestandaryzowanej, więc nie liczy się to jako różnica. Możesz porównać tylko jabłka z jabłkami, a nie jabłkami z gruszkami.
Alok Save
3
Nie ma takiej gwarancji EXIT_SUCCESS == 0. Z drugiej strony nie ma dobrego powodu, aby tak nie było.
Keith Thompson
@KeithThompson: dlaczego Nie ma gwarancji, że EXIT_SUCCESS == 0.? Proszę wyjaśnij to jaśniej.
Destructor
2
@PravasiMeet: System może mieć więcej niż jedną wartość wskazującą na sukces.
Keith Thompson
11

0 jest z definicji magiczną liczbą. EXIT_SUCCESS jest prawie zawsze równe 0, na szczęście. Dlaczego więc nie wrócić / wyjść z 0?

exit (EXIT_SUCCESS); ma bardzo jasne znaczenie.

wyjście (0); z drugiej strony jest pod pewnymi względami sprzeczny z intuicją. Ktoś, kto nie jest zaznajomiony z zachowaniem powłoki, może założyć, że 0 == false == złe, tak jak każde inne użycie 0 w C. Ale nie - w tym jednym szczególnym przypadku 0 == sukces == dobrze. Dla większości doświadczonych deweloperów nie będzie to problemem. Ale po co potykać się z nowym facetem bez absolutnie żadnego powodu?

tl; dr - jeśli istnieje określona stała dla twojej magicznej liczby, prawie nigdy nie ma powodu, aby nie używać tej stałej w pierwszej kolejności. Jest łatwiejszy do przeszukiwania, często bardziej przejrzysty itp. I nic Cię to nie kosztuje.

James
źródło
Myślę, że twoje komentarze o ludziach, którzy oczekują, że 0 będzie automatycznie złe, są chybione. Bardzo wiele interfejsów API używa 0 do sukcesu i wartości innej niż 0 do niepowodzenia, nawet w standardowej bibliotece. Np stdlib ( fclose(), setvbuf()...), POSIX ( listen(), pthread_create(), pipe(), ...) i wiele, wiele innych bibliotek (np OpenGL [ glGetError()], zlib [ deflate()/ inflate()/ ...], SDL [ SDL_CreateWindowAndRenderer()/ ...], a więcej).
Tim Čas
2
Jasne, są inne przypadki, w których 0 jest używane do określenia „sukcesu”, ale ma rację co do tego, że jest to mylące.
Paul Wintz
10

To niekończąca się historia, która odzwierciedla ograniczenia (mit) „ponad wszystko interoperacyjności i przenośności”.

To, co program powinien zwrócić, aby wskazać „sukces”, powinno być określone przez to, kto otrzymuje wartość (system operacyjny lub proces, który wywołał program), a nie przez specyfikację języka.

Jednak programiści lubią pisać kod w „przenośny sposób” i dlatego wymyślają swój własny model pojęcia „systemu operacyjnego” definiującego wartości symboliczne do zwrócenia.

Teraz, w scenariuszu wiele-do-wielu (gdzie wiele języków służy do pisania programów w wielu systemach) zgodność między konwencją językową określającą „sukces” a konwencją systemu operacyjnego (której nikt nie może przyznać, że jest zawsze taka sama) powinna być obsługiwane przez konkretną implementację biblioteki dla określonej platformy docelowej.

Ale - niestety - te koncepcje nie były tak jasne w czasie wdrażania języka C (głównie do pisania jądra UNIX), a gigagramy książek, w których napisano „powrót 0 oznacza sukces”, ponieważ było to prawdą w systemie operacyjnym w tym razem mając kompilator C.

Od tego czasu nie dokonano żadnej jasnej standaryzacji co do tego, jak należy postępować z taką korespondencją. C i C ++ mają swoją własną definicję „wartości zwracanych”, ale nikt nie przyznaje odpowiedniego tłumaczenia systemu operacyjnego (lub lepiej: żadna dokumentacja kompilatora nie mówi o tym). 0 oznacza sukces, jeśli jest prawdziwe dla UNIX - LINUX i - z niezależnych powodów - także dla Windows, a to obejmuje 90% istniejących "komputerów konsumenckich", które - w większości przypadków - pomijają zwracaną wartość (więc możemy dyskutujemy od dziesięcioleci, ale nikt tego nigdy nie zauważy!)

W tym scenariuszu, przed podjęciem decyzji, zadaj następujące pytania: - Czy jestem zainteresowany przekazaniem dzwoniącemu czegoś na temat mojego obecnego? (Jeśli zawsze zwracam 0 ... nie ma pojęcia o tym wszystkim) - Czy mój rozmówca ma konwencje dotyczące tej komunikacji? (Zauważ, że pojedyncza wartość nie jest konwencją: to nie pozwala na jakąkolwiek reprezentację informacji)

Jeśli obie te odpowiedzi brzmią „nie”, prawdopodobnie dobrym rozwiązaniem jest w ogóle nie pisać głównej instrukcji powrotu. (I pozwól kompilatorowi zdecydować, w odniesieniu do celu pracuje).

Jeśli nie ma żadnej konwencji, 0 = sukces spełnia większość sytuacji (a używanie symboli może być problematyczne, jeśli wprowadzają konwencję).

Jeśli konwencje istnieją, upewnij się, że używasz symbolicznych stałych, które są z nimi spójne (i zapewniaj spójność konwencji, a nie spójność wartości, między platformami).

Emilio Garavaglia
źródło
4

Kiedy zaczniesz pisać kod, który może zwrócić niezliczone statusy wyjścia, zaczynasz #defineje wszystkie. W tym przypadku EXIT_SUCCESSma to sens w kontekście nie bycia „ magiczną liczbą ”. To sprawia, że ​​twój kod jest bardziej czytelny, ponieważ każdy inny kod wyjścia będzie EXIT_SOMETHING. Jeśli po prostu napiszesz program, który zwróci po zakończeniu, return 0jest prawidłowy i prawdopodobnie nawet bardziej przejrzysty, ponieważ sugeruje brak wyrafinowanej struktury kodu powrotu.

Phonon
źródło
0

To, co zwracasz z programu, to tylko konwencja.

Nie, nie przychodzą mi do głowy żadne okoliczności, w których „EXIT_SUCCESS” nie byłoby „0”.

Osobiście poleciłbym „0”.

MOIM ZDANIEM...

paulsm4
źródło
1
Programuję w C ++ od 10 lat i nadal nie pamiętam, czy 0 oznacza sukces, czy porażkę w zakresie zwracanych wartości.
lahjaton_j
@lahjaton_j, rozumiem. Uważa, że dzieje się tak dlatego, że jest sprzeczne z intuicją: 0jest fałszywe, a wiele funkcji powraca 0po niepowodzeniu / nic nie robiąc.
znaczenie-ma znaczenie
-5

Niektóre kompilatory mogą powodować z tym problemy - na kompilatorze Mac C ++ EXIT_SUCCESS działało dobrze, ale na kompatybilnym z Linux C ++ musiałem dodać cstdlib, aby wiedzieć, co to jest EXIT_SUCCESS. Poza tym są jednym i tym samym.

Oburęczny
źródło
Miałem na myśli, że na Macu EXIT_SUCCESS działało bez włączania cstdlib.
Oburęczny
4
Jeśli EXIT_SUCCESSdziałał bez uwzględnienia jednego <stdlib.h>lub <cstdlib>drugiego, musiał go zdefiniować inny nagłówek, bezpośrednio lub pośrednio. W C ++ jest to typowe dla standardowych nagłówków do #includeinnych standardowych nagłówków. Jeśli to kompiluje się bez błędów: oznacza int main() { return EXIT_SUCCESS; }to, że Twój kompilator prawdopodobnie zawiera błędy.
Keith Thompson