Domanda

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

exit () fa qualcosa di speciale che restituisce ?

È stato utile?

Soluzione

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 () , non verrà chiamato nessun distruttore per i miei oggetti con ambito locale! Rileggilo. exit () non ritorna . Ciò significa che una volta che lo chiamo, non ci sono "backsies". Gli oggetti che hai creato in quella funzione non verranno distrutti. Spesso questo non ha implicazioni, ma a volte lo fa, come chiudere i file (sicuramente vuoi che tutti i tuoi dati vengano scaricati su disco?).

Nota che gli oggetti statici verranno ripuliti anche se chiami exit () . Infine, nota che se usi abort () , nessun oggetto verrà distrutto. Cioè, nessun oggetto globale, nessun oggetto statico e nessun oggetto locale avranno i loro distruttori chiamati.

Procedi con cautela nel favorire l'uscita rispetto al ritorno.

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

Altri suggerimenti

Un'altra differenza: exit è una libreria standard funzione quindi è necessario includere intestazioni e collegamento con lo standard biblioteca. Per illustrare (in C ++), questo è un programma valido:

int main() { return 0; }

ma per usare exit devi includere:

#include <stdlib.h>
int main() { exit(EXIT_SUCCESS); }

Inoltre, ciò aggiunge un ulteriore presupposto: la chiamata di exit da main ha gli stessi effetti collaterali della restituzione di zero. Come altri hanno sottolineato, questo dipende dal tipo di eseguibile che stai costruendo (ovvero, chi sta chiamando main ). Stai codificando un'app che utilizza C-runtime? Un plugin Maya? Un servizio Windows? Un autista? Ogni caso richiederà una ricerca per vedere se exit è equivalente a return . IMHO usando exit quando intendi davvero return rende il codice più confuso. OTOH, se intendi davvero esci , allora usalo sicuramente.

Esiste almeno un motivo per preferire exit : se uno dei tuoi gestori atexit fa riferimento a dati di durata della memorizzazione automatica in main oppure se hai utilizzato setvbuf o setbuf per assegnare a uno dei flussi standard un buffer di durata della memorizzazione automatica in main , quindi di ritorno da main produce un comportamento indefinito, ma chiamare exit è valido.

Un altro potenziale utilizzo (di solito riservato ai programmi giocattolo, tuttavia) è 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 offrono un trattamento speciale per main e presumono che restituisca 0 se non esiste un'istruzione esplicita return . Dato il seguente codice:

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

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

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

I STRONGLY secondo il commento di R. sull'utilizzo di exit () al fine di evitare che la memorizzazione automatica in main () venga recuperata prima che il programma effettivamente termini. Un'istruzione return X; in main () non è esattamente equivalente a una chiamata a exit (X); , poiché l'archiviazione dinamica di < code> main () scompare quando ritorna main () , ma non svanisce se viene invece effettuata una chiamata a exit () .

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

Dopotutto, se vuoi terminare il tuo programma da qualsiasi altra funzione tranne main () devi devi chiamare exit () . Fare così in modo coerente in main () rende anche il tuo codice molto più leggibile, e rende anche molto più facile per chiunque ricodificare il tuo codice; cioè il codice copiato da main () in qualche altra funzione non si comporterà in modo errato a causa delle dichiarazioni accidentali return che avrebbe dovuto essere stato exit ( ) chiamate.

Quindi, combinando tutti questi punti insieme la conclusione è che è una cattiva abitudine , almeno per C, usare un'istruzione return per terminare il programma in < code> main () .

  

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

Con alcuni compilatori per piattaforme 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 a l'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 diversi sistemi operativi hanno convenzioni diverse per l'interpretazione dei valori di uscita. Su molti sistemi (MOLTI!), 0 significa successo e qualsiasi altra cosa è un fallimento. Ma su, diciamo, VMS, valori dispari significano successo e anche quelli significano fallimento. Se hai restituito 0 da main () , un utente VMS vedrebbe un brutto messaggio su una violazione di accesso. In realtà non c'era una violazione di accesso - era semplicemente il messaggio standard associato al codice di errore 0.

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

Lo standard, quindi, ti mette in relazione con VMS, in quanto non lascia un modo standard per restituire un codice fallimento che sembra avere il valore 0.

Il compilatore VAX / VMS C dell'inizio degli anni '90 non interpretava quindi il valore di ritorno da main () , ma semplicemente restituiva qualsiasi valore all'ambiente host. Ma se utilizzassi exit () , farebbe ciò che lo standard richiesto: tradurre EXIT_SUCCESS (o 0 ) in un codice di successo e EXIT_FAILURE in un codice di errore generico. Per usare EXIT_SUCCESS , hai dovuto passare a exit () , non puoi restituirlo da main () . Non so se versioni più moderne di quel compilatore abbiano conservato quel comportamento.

Un programma C portatile usato per assomigliare a questo:

#include <stdio.h>
#include <stdlib.h>

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 bene, la convenzione VMS per i valori di uscita è più sfumata di pari / dispari. In realtà usa 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.

In C che ritorna da main è esattamente lo stesso che chiamare exit con lo stesso valore.

Sezione 5.1.2.2.3 della C standard afferma:

  

Se il tipo restituito della funzione principale è un tipo compatibile con int   , un ritorno dalla chiamata iniziale alla funzione principale equivale a   chiamando la funzione di uscita con il valore restituito dal principale   funzione come argomento ; 11) raggiungere il} che termina il   la funzione principale restituisce un valore pari a 0. Se il tipo restituito è   non compatibile con int, lo stato di terminazione restituito a   l'ambiente host non è specificato.

Le regole per C ++ sono leggermente diverse come indicato in altre risposte.

Esiste effettivamente una differenza tra exit (0) e return (0) in main & # 8211; & nbsp; quando il tuo < La funzione code> main viene chiamata più volte.

Il seguente programma

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
  if (argc == 0)
    return(0);
  printf("%d", main(argc - 1, argv));
}

Esegui come

./program 0 0 0 0

Produrrà il seguente output:

00000

Comunque questo:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
  if (argc == 0)
    exit(0);
  printf("%d", main(argc - 1, argv));
}

Non stampa nulla indipendentemente dagli argomenti.

Se sei sicuro che nessuno chiamerà mai esplicitamente il tuo main non è tecnicamente una grande differenza in generale, ma mantenere un codice più chiaro exit sarebbe molto meglio. Se per qualche motivo vuoi chiamare main & # 8211; dovresti adattarlo alle tue esigenze.

Parlando di C.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top