2010-08-11 11 views

risposta

115
  • ritorno è un'istruzione del linguaggio che ritorna da una chiamata di funzione.
  • exit è una chiamata di sistema (non un'istruzione di lingua) che termina il processo corrente.

L'unico caso in cui sia fare (quasi) la stessa cosa è nella funzione main(), come un ritorno al collettore principale esegue un exit().

Esempio con return:

#include <stdio.h> 

void f(){ 
    printf("Executing f\n"); 
    return; 
} 

int main(){ 
    f(); 
    printf("Back from f\n"); 
} 

Se si esegue questo programma esso stampa:

Executing f 
Back from f 

Un altro esempio per exit():

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

void f(){ 
    printf("Executing f\n"); 
    exit(0); 
} 

int main(){ 
    f(); 
    printf("Back from f\n"); 
} 

Se si esegue questo programma esso stampa:

Executing f 

Non si può mai ottenere "Back from f". Si noti inoltre che lo #include <stdlib.h> è necessario per chiamare la funzione di libreria exit().

Si noti inoltre che il parametro di exit() è un numero intero (è lo stato di ritorno del processo che può essere ottenuto dal processo di avvio, l'utilizzo convenzionale è 0 per il successo o qualsiasi altro valore per un errore).

Il parametro dell'istruzione return è qualunque sia il tipo restituito della funzione. Se la funzione restituisce void, è possibile omettere il ritorno alla fine della funzione.

Ultimo punto, exit() disponibile in due versioni _exit() e exit(). La differenza tra i moduli è che le funzioni delle chiamate exit() (e ritorno dalle principali) registrate utilizzando atexit() o on_exit() prima di terminare realmente il processo mentre _exit() (da #include <unistd.h> o anche _Exit da #include <stdlib.h>) termina immediatamente il processo.

Ora ci sono anche problemi specifici per C++.

C++ esegue molto più lavoro di C quando esce dalle funzioni (return -ing). Nello specifico, chiama i distruttori di oggetti locali che escono dallo scopo. Nella maggior parte dei casi i programmatori non si preoccuperanno molto dello stato di un programma dopo che il processo si è fermato, quindi non farebbe molta differenza: la memoria allocata sarà liberata, il file ressource chiuso e così via. Ma può essere importante se il tuo distruttore esegue IO. Ad esempio, il C++ automatico OStream creato localmente non verrà svuotato su una chiamata per uscire e potresti perdere alcuni dati non aggiornati (d'altra parte lo stallo statico OStream verrà svuotato).

Ciò non accadrà se si utilizzano i vecchi flussi C FILE*. Questi saranno scaricati su exit(). In realtà, la regola è la stessa che per le funzioni di uscita registrate, FILE* verrà svuotato su tutte le terminazioni normali, che include exit(), ma non le chiamate a _exit() o abort().

Si dovrebbe anche tenere presente che C++ fornisce un terzo modo per uscire da una funzione: lanciare un'eccezione. Questo modo di uscire da una funzione è il distruttore di chiamata. Se non viene catturato da nessuna parte nella catena di chiamanti, l'eccezione può salire alla funzione main() e terminare il processo.

I distruttori di oggetti C++ statici (globali) verranno chiamati se si chiama return da main() o exit() in qualsiasi punto del programma. Non verranno chiamati se il programma viene terminato utilizzando _exit() o abort(). abort() è utile soprattutto in modalità di debug con lo scopo di arrestare immediatamente il programma e ottenere una traccia di stack (per l'analisi post mortem). Di solito è nascosto dietro la macro assert() attiva solo in modalità di debug.

Quando è utile exit()?

exit() significa che si desidera interrompere immediatamente il processo corrente. Può essere utile per la gestione degli errori quando incontriamo un qualche tipo di problema irrecuperabile che non consente al tuo codice di fare qualcosa di più utile. È spesso utile quando il flusso di controllo è complicato e i codici di errore devono essere propagati su tutti i lati. Ma sappi che questa è una cattiva pratica di programmazione. La chiusura silenziosa del processo è nella maggior parte dei casi il comportamento peggiore e la gestione degli errori effettiva dovrebbe essere preferibile (o in C++ utilizzando eccezioni).

Le chiamate dirette a exit() sono particolarmente negative se eseguite nelle librerie in quanto condannerà l'utente della libreria e dovrebbe essere la scelta di una libreria utente per implementare una sorta di ripristino degli errori o meno. Se si desidera un esempio del perché chiamare exit() da una libreria non sia corretto, per esempio, le persone chiedono a this question.

C'è un uso legittimo indiscusso di exit() come modo per terminare un processo figlio avviato da fork() su Sistemi operativi che lo supportano. Tornando al codice prima di fork() è di solito una cattiva idea. Questo è il motivo per cui le funzioni della famiglia exec() non torneranno mai al chiamante.

+6

uscita() non è una chiamata di sistema –

+0

@anon: hai ragione, tecnicamente è un ritorno al sistema, ma non c'è molta differenza. – kriss

+0

@JonathanLeffler In 'main()' è preferibile usare 'return' o' exit'? Cerca il codice [THIS] exmple (https://gist.github.com/anonymous/c293fbd346a534912e69). –

10

In C, non c'è molta differenza quando viene utilizzato nella funzione di avvio del programma (che può essere main(), wmain(), _tmain() o il nome predefinito utilizzato dal compilatore).

Se return in main(), il controllo ritorna alla funzione _start() nella libreria C che originariamente iniziato il vostro programma, che poi chiama exit() comunque. Quindi non importa quale usi.

+1

Non importa. exit() termina immediatamente il programma, indipendentemente da dove viene chiamato. return esce solo dalla funzione corrente. l'unica posizione in cui fanno la stessa cosa è in main() – Amy

+0

Grazie, ho corretto il testo. Non è necessariamente solo in main(), poiché non tutti i compilatori usano lo stesso nome di funzione per la funzione di avvio. –

+7

Immagino che tu scriva tutti i tuoi programmi in un'unica grande funzione principale? ;-) –

13

ho scritto due programmi:

int main(){return 0;} 

e

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

Dopo l'esecuzione gcc -S -O1.Ecco quello che ho trovato a guardare in fase di montaggio (solo parti importanti):

main: 
    movl $0, %eax /* setting return value */ 
    ret     /* return from main */ 

e

main: 
    subq $8, %rsp /* reserving some space */ 
    movl $0, %edi /* setting return value */ 
    call exit  /* calling exit function */ 
         /* magic and machine specific wizardry after this call */ 

Quindi la mia conclusione è: utilizzare return quando è possibile, e exit() quando è necessario.

1

le uscite dichiarazione di ritorno dalla funzione corrente e uscire() esce dal programma

they are the same when used in main() function 

ritorno è anche una dichiarazione mentre exit() è una funzione che richiede di intestazione del file stdlb.h

Problemi correlati