dichiarazione di ritorno vs exit () in main ()

Dovrei usare exit() o semplicemente return istruzioni in main() ? Personalmente preferisco le dichiarazioni di return perché sento che è come leggere qualsiasi altra funzione e il controllo di stream quando sto leggendo il codice è scorrevole (secondo me). E anche se voglio refactoring la funzione main() , avere return sembra una scelta migliore di exit() .

Exit exit() fa qualcosa di speciale che non return ?

In realtà, c’è una differenza, ma è sottile. Ha più implicazioni per C ++, ma le differenze sono importanti.

Quando chiamo return in main() , i distruttori verranno chiamati per i miei oggetti con ambito locale. Se chiamo exit() , nessun distruttore verrà chiamato per i miei oggetti con scope locale! Rileggere questo. exit() non restituisce . Ciò significa che una volta che lo chiamo, non ci sono “backsies”. Qualsiasi object che hai creato in quella funzione non verrà distrutto. Spesso questo non ha implicazioni, ma a volte lo fa, come chiudere i file (sicuramente si desidera che tutti i dati vengano scaricati su disco?).

Si noti che gli oggetti static verranno eliminati anche se si chiama exit() . Infine, nota che se usi abort() , nessun object verrà distrutto. Cioè, nessun object globale, nessun object statico e nessun object locale chiameranno i loro distruttori.

Procedere con caucanvas nel favorire l’uscita dal ritorno.

http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a

Un’altra differenza: l’ exit è una funzione di libreria standard, quindi è necessario includere intestazioni e collegamenti con la libreria standard. Per illustrare (in C ++), questo è un programma valido:

 int main() { return 0; } 

ma per usare exit avrai bisogno di includere:

 #include  int main() { exit(EXIT_SUCCESS); } 

Inoltre, ciò aggiunge un’ipotesi addizionale: l’ exit chiamata dal main ha gli stessi effetti collaterali del return zero. Come altri hanno sottolineato, ciò dipende dal tipo di eseguibile che stai creando (ovvero, chi sta chiamando main ). Stai codificando un’app che utilizza il runtime C? Un plugin Maya? Un servizio di Windows? Un autista? Ogni caso richiederà una ricerca per vedere se l’ exit è equivalente al return . L’IMHO che usa exit quando intendi davvero return rende solo il codice più confuso. OTOH, se vuoi davvero exit , allora usalo con tutti i mezzi.

C’è almeno un motivo per preferire l’ exit : se qualcuno dei tuoi gestori di atexit riferimento a dati di durata di archiviazione automatica in main , o se hai usato setvbuf o setbuf per assegnare a uno dei flussi standard un buffer di durata di archiviazione automatica in main , quindi il ritorno da main produce un comportamento non definito, ma la chiamata exit è valida.

Un altro utilizzo potenziale (solitamente riservato ai programmi giocattolo, comunque) è quello di uscire da un programma con invocazioni ricorsive di main .

Uso sempre return perché il prototipo standard per main() dice che restituisce un int .

Detto questo, alcune versioni degli standard danno un trattamento speciale main e assumono che restituisca 0 se non c’è un’istruzione di return esplicita. Dato il seguente codice:

 int foo() {} int main(int argc, char *argv[]) {} 

G ++ genera solo un avvertimento per foo() e ignora il ritorno mancante dal main :

 % g++ -Wall -c foo.cc foo.cc: In function 'int foo()': foo.cc:1: warning: control reaches end of non-void function 

FACILMENTE secondo il commento di R. sull’utilizzo di exit () per evitare che lo storage automatico in main() venga reclamato prima che il programma finisca effettivamente. Un return X; l’istruzione in main() non è esattamente equivalente a una call to exit(X); , poiché la memoria dynamic di main() cancella quando main() ritorna, ma non svanisce se viene effettuata una chiamata a exit() .

Inoltre, in C o in un linguaggio simile a C un’istruzione return accenna fortemente al lettore che l’esecuzione continuerà nella funzione di chiamata e mentre questa continuazione dell’esecuzione è di solito tecnicamente vera se si conta la routine di avvio C che ha chiamato il main() funzione, non è esattamente ciò che intendi quando intendi terminare il processo.

Dopotutto, se vuoi terminare il tuo programma da qualsiasi altra funzione tranne main() devi chiamare exit() . Farlo in modo consistente anche in main() rende il tuo codice molto più leggibile e rende anche più facile a chiunque ridimensionare il tuo codice; cioè il codice copiato da main() a qualche altra funzione non si comporta in modo anomalo a causa di dichiarazioni di return accidentali che avrebbero dovuto essere chiamate exit() .

Quindi, combinando tutti questi punti, la conclusione è che è una ctriggers abitudine , almeno per C, usare un’istruzione return per terminare il programma in main() .

Exit () fa qualcosa di speciale che ‘return’ non fa?

Con alcuni compilatori per piattaforms non comuni, exit() potrebbe tradurre il suo argomento nel valore di uscita del programma mentre un ritorno da main() potrebbe semplicemente passare il valore direttamente all’ambiente host senza alcuna traduzione.

Lo standard richiede un comportamento identico in questi casi (in particolare, dice che restituire qualcosa che è int -compatibile da main() dovrebbe essere equivalente a chiamare exit() con quel valore). Il problema è che i diversi SO hanno convenzioni diverse per l’interpretazione dei valori di uscita. Su molti (molti!) Sistemi, 0 significa successo e qualsiasi altra cosa è un fallimento. Ma su, per esempio, VMS, valori dispari significano successo e anche quelli significano fallimento. Se hai restituito 0 da main() , un utente VMS vedrebbe un messaggio sgradevole su una violazione di accesso. Non c’era in realtà una violazione di accesso – era semplicemente il messaggio standard associato al codice di errore 0.

Poi ANSI è arrivato e ha benedetto EXIT_SUCCESS e EXIT_FAILURE come argomenti da passare a exit() . Lo standard dice anche che exit(0) dovrebbe comportarsi in modo identico per exit(EXIT_SUCCESS) , quindi la maggior parte delle implementazioni definisce EXIT_SUCCESS su 0 .

Lo standard, quindi, ti mette in un bind su VMS, in quanto non lascia alcun modo standard per restituire un codice di errore che ha il valore 0.

Il compilatore VAX / VMS C dell’inizio degli anni ’90 quindi non interpretava il valore restituito da main() , restituiva semplicemente qualsiasi valore all’ambiente host. Ma se hai usato exit() , farebbe quello che è richiesto dallo standard: traduci EXIT_SUCCESS (o 0 ) in un codice di successo e EXIT_FAILURE in un codice di errore generico. Per utilizzare EXIT_SUCCESS , è necessario passarlo a exit() , non è ansible restituirlo da main() . Non so se versioni più moderne di quel compilatore abbiano mantenuto quel comportamento.

Un programma C portatile usato per assomigliare a questo:

 #include  #include  int main() { printf("Hello, World!\n"); exit(EXIT_SUCCESS); /* to get good return value to OS */ /*NOTREACHED*/ /* to silence lint warning */ return 0; /* to silence compiler warning */ } 

A parte: se ricordo correttamente, la convenzione VMS per i valori di uscita è più sfumata di pari / dispari. In realtà utilizza qualcosa come i tre bit bassi per codificare un livello di gravità. In generale, tuttavia, i livelli di gravità dispari indicavano il successo o informazioni varie e quelli pari indicavano errori.