W rzeczywistości jest różnica, ale jest subtelna. Ma więcej implikacji dla C ++, ale różnice są ważne.
Kiedy zadzwonić return
w main()
destruktory zostanie wywołana dla moich lokalnie scoped obiektów. Jeśli zadzwonię exit()
, żaden obiekt destruktor nie zostanie wywołany dla moich obiektów o lokalnym zasięgu! Przeczytaj to ponownie. exit()
nie wraca . Oznacza to, że gdy go nazywam, nie ma „żadnych backsies”. Wszelkie obiekty utworzone w tej funkcji nie zostaną zniszczone. Często nie ma to żadnych implikacji, ale czasem tak, jak zamykanie plików (na pewno chcesz, aby wszystkie twoje dane zostały zrzucone na dysk?).
Pamiętaj, że static
obiekty zostaną wyczyszczone, nawet jeśli zadzwonisz exit()
. Na koniec zauważ, że jeśli użyjesz abort()
, żadne przedmioty nie zostaną zniszczone. Oznacza to, że nie ma obiektów globalnych, żadnych obiektów statycznych i żadnych obiektów lokalnych.
Postępuj ostrożnie, preferując wyjście zamiast powrotu.
http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a
thread_local
że zostaną wywołane destruktory obiektów. Niszczyciele dla innych obiektów lokalnych nadal nie są wywoływane. ideone.com/Y6Dh3fexit()
czystym zamykaniem plików jest w rzeczywistości błędny. Jedynym czasem, w którym dane mogą nie zostać usunięte, jest odwrotny przypadek: tj. Jeśli ktoś korzystareturn
zmain()
i wywołujesetbuf()
lubsetvbuf()
bufor jest zadeklarowany jako automatyczne przechowywanie wmain()
(jak omówiono w odpowiedzi R. poniżej). Szkoda, że to pytanie jest oznaczone zarówno C, jak i C ++ (i stylem kodowania - to nie jest problem ze stylem!).Kolejna różnica:
exit
jest funkcją biblioteki standardowej, więc musisz dołączyć nagłówki i połączyć się ze standardową biblioteką. Aby to zilustrować (w C ++), jest to poprawny program:ale do użycia
exit
potrzebujesz:Dodatkowo dodaje to dodatkowe założenie: że sprawdzanie
exit
zmain
ma takie same skutki uboczne jak zwracanie zera. Jak zauważyli inni, zależy to od tego, jaki rodzaj pliku wykonywalnego budujesz (tj. Kto dzwonimain
). Czy kodujesz aplikację korzystającą ze środowiska wykonawczego C? Wtyczka Maya? Usługa Windows? Kierowca? Każdy przypadek będzie wymagał badań, aby sprawdzić, czyexit
jest równoważnyreturn
. Używanie IMHO,exit
gdy naprawdę masz na myśli,return
sprawia, że kod jest bardziej mylący. OTOH, jeśli naprawdę masz na myśliexit
, to na pewno wykorzystaj to.źródło
Istnieje co najmniej jeden powód, aby preferować
exit
: jeśli któryś z twoich programówatexit
obsługi odnosi się do danych dotyczących czasu automatycznego przechowywania wmain
lub jeśli używałeśsetvbuf
lubsetbuf
przypisałeś do jednego ze standardowych strumieni bufor automatycznego czasu przechowywaniamain
, to wracasz zmain
produkcji niezdefiniowane zachowanie, ale wywołanieexit
jest prawidłowe.Innym potencjalnym zastosowaniem (zwykle zarezerwowanym dla programów zabawkowych) jest wyjście z programu z rekurencyjnymi wywołaniami
main
.źródło
main()
- to po prostu funkcja jak każda inna. Z drugiej strony, ponieważ ma on specjalne wzmiankę w normie, norma musi być dość ostrożna w kwestii tego, jak definiuje, jakmain()
i rzeczy, które są jej bliskie i drogie. Jednak w końcu standard nie wymaga (i nie musi ) wymagać od kompilatorów robienia czegokolwiek specjalnego na temat automatycznego przechowywania wmain()
. Przeczytaj uważnie przypis 11 pod akapitem, do którego odwołujesz się w komentarzu.Zawsze używam,
return
ponieważ standardowy prototyp dlamain()
mówi, że zwraca anint
.To powiedziawszy, niektóre wersje standardów zapewniają
main
specjalne traktowanie i zakładają, że zwraca 0, jeśli nie ma wyraźnegoreturn
oświadczenia. Biorąc pod uwagę następujący kod:G ++ generuje tylko ostrzeżenie
foo()
i ignoruje brakujący zwrot zmain
:źródło
return
aby zakończyć jej wykonywanie. Wywołanieexit()
jest również prawidłowym, a czasem koniecznym sposobem zakończenia wykonywania dowolnej funkcji. Rzeczywiście, jak ja i inni opisaliśmy gdzie indziej, wywoływanieexit()
nawet zmain()
przekazuje o wiele bardziej wyraźną intencję wyjścia z całego procesu, zachowuje automatyczne przechowywanie do momentu zakończenia procesu i ułatwia konserwację podczas przyszłego refaktoryzacji kodu. Dla C stosującreturn
wmain()
kiedy intencją jest, aby zakończyć proces jest więc bez wątpienia złą praktyką.ja SILNIE drugi komentarz na temat korzystania przez R. exit () w celu uniknięcia konieczności automatycznego przechowywania w
main()
regeneracji zanim program w zasadzie kończy.return X;
Oświadczenie wmain()
nie jest dokładnie równoważne wywołaniuexit(X);
, ponieważ dynamiczny przechowywaniamain()
znika, gdymain()
powróci, ale nie znikają, jeśli wywołanieexit()
jest wykonany zamiast.Ponadto w języku C lub dowolnym języku podobnym do C
return
instrukcja zdecydowanie wskazuje czytelnikowi, że wykonanie będzie kontynuowane w funkcji wywołującej i chociaż ta kontynuacja wykonywania jest zwykle technicznie prawdziwa, jeśli policzy się procedurę uruchamiania C, która wywołała twojąmain()
funkcję, nie jest dokładnie to, co masz na myśli, kiedy chcesz zakończyć proces.W końcu, jeśli chcesz zakończyć swój program z jakiejkolwiek innej funkcji, z wyjątkiem tego,
main()
że musisz wywołaćexit()
. Konsekwentne postępowanie w tenmain()
sposób powoduje, że kod jest znacznie bardziej czytelny, a także ułatwia każdemu ponowne przeliczenie kodu; tzn. kod skopiowany zmain()
innej funkcji nie będzie źle działał z powodu przypadkowychreturn
instrukcji, które powinny były byćexit()
wywołaniami.Tak więc, łącząc wszystkie te punkty razem, wniosek jest taki, że złym nawykiem , przynajmniej dla C, jest użycie
return
instrukcji do zakończenia programu wmain()
.źródło
exit()
, ale używaj go, jeśli athrow
lubabort()
alternatywy nie działają w określonym kontekście. Ale szczególnie unikajexit()
w main i używaj return in main zamiast typowej praktyki.W przypadku niektórych kompilatorów dla nietypowych platform
exit()
może tłumaczyć swój argument na wartość wyjściową programu, podczas gdy zwrot zmain()
może po prostu przekazać wartość bezpośrednio do środowiska hosta bez żadnego tłumaczenia.Standard wymaga identycznego zachowania w tych przypadkach (konkretnie, to mówi powrocie coś, co jest
int
-Kompatybilny zemain()
powinno być równoznaczne z wywołaniemexit()
tej wartości). Problem polega na tym, że różne systemy operacyjne mają różne konwencje interpretowania wartości wyjściowych. W wielu systemach (WIELE!) 0 oznacza sukces, a wszystko inne jest porażką. Ale przy, powiedzmy, VMS, nieparzyste wartości oznaczają sukces, a nawet te oznaczają porażkę. Jeśli zwróciłeś 0 zmain()
, użytkownik VMS zobaczy nieprzyjemną wiadomość o naruszeniu dostępu. W rzeczywistości nie doszło do naruszenia praw dostępu - był to po prostu standardowy komunikat związany z kodem błędu 0.Potem przyszedł ANSI i pobłogosławił,
EXIT_SUCCESS
aEXIT_FAILURE
jako argumenty można przekazaćexit()
. Norma mówi również, żeexit(0)
należy zachowywać się identycznieexit(EXIT_SUCCESS)
, więc większość implementacji zdefiniowaćEXIT_SUCCESS
do0
.Dlatego standard wprowadza cię w VMS, ponieważ nie pozostawia żadnego standardowego sposobu na zwrócenie kodu błędu , który ma wartość 0.
Kompilator VAX / VMS C z wczesnych lat 90. nie interpretował zatem wartości zwracanej
main()
, po prostu zwracał dowolną wartość do środowiska hosta. Ale jeśli go użyjeszexit()
, zrobi to, czego wymaga standard: przetłumaczEXIT_SUCCESS
(lub0
) na kod sukcesu iEXIT_FAILURE
na ogólny kod błędu. Aby użyćEXIT_SUCCESS
, trzeba było przekazać goexit()
, z którego nie można było go zwrócićmain()
. Nie wiem, czy nowsze wersje tego kompilatora zachowały to zachowanie.Przenośny program C wyglądał tak:
Na bok: jeśli dobrze pamiętam, konwencja VMS dla wartości wyjściowych jest bardziej szczegółowa niż nieparzysta / parzysta. W rzeczywistości używa czegoś takiego jak trzy niskie bity do kodowania poziomu ważności. Ogólnie jednak, nieparzyste poziomy dotkliwości wskazywały na sukces lub różne informacje, a parzyste wskazywały błędy.
źródło
returned
przezmain
odmiennie od wartości przekazanegoexit
- ale średnia specjalnie mówi: „Jeśli typ powrótmain
funkcji jest kompatybilny z typemint
, powrót z pierwszego połączenia domain
funkcji jest odpowiednik wywołaniaexit
funkcji z wartością zwróconą przezmain
funkcję jako argument ". To jest C11; C89 / C90 miał prawie takie samo brzmienie.EXIT_SUCCESS
, nie było możliwości zwrócenia specyficznego dla platformy stanu awarii z wartością 0, co może być przyczyną, dla której niektóre kompilatory ery traktowane jako powrót-z-głównego iexit()
inaczej.W C powrót z
main
jest dokładnie tym samym, co wywołanieexit
z tą samą wartością.Sekcja 5.1.2.2.3 normy C stanowi:
Reguły dla C ++ są nieco inne, jak wspomniano w innych odpowiedziach.
źródło
W rzeczywistości istnieje różnica pomiędzy
exit(0)
ireturn(0)
wewnątrzmain
- gdy twojamain
funkcja jest wywoływana wiele razy.Poniższy program
Uruchom jako
Spowoduje następujące wyniki:
Jednak ten:
Nie wydrukuje niczego bez względu na argumenty.
Jeśli masz pewność, że nikt nigdy nie zadzwoni
main
wprost, nie jest to technicznie duża różnica w ogóle, ale utrzymanie wyraźniejszego koduexit
wyglądałoby znacznie lepiej. Jeśli z jakiegoś powodu chcesz zadzwonićmain
- powinieneś dostosować go do swoich potrzeb.Mówiąc o C.
źródło