Was ist der Unterschied zwischen exit () und abort ()?


130

Was ist in C und C ++ der Unterschied zwischen exit()und abort()? Ich versuche mein Programm nach einem Fehler zu beenden (keine Ausnahme).

Antworten:


116

abort()Beendet Ihr Programm, ohne die zuerst registrierten Funktionen aufzurufen atexit()und ohne zuerst die Destruktoren der Objekte aufzurufen. exit()macht beides, bevor Sie Ihr Programm beenden. Destruktoren für automatische Objekte werden jedoch nicht aufgerufen. So

A a;
void test() { 
    static A b;
    A c;
    exit(0);
}

Wird zerstören aund brichtig, aber wird nicht Destruktoren von nennen c. abort()würde keine Destruktoren von beiden Objekten nennen. Da dies unglücklich ist, beschreibt der C ++ - Standard einen alternativen Mechanismus, der eine ordnungsgemäße Beendigung sicherstellt:

Objekte mit automatischer Speicherdauer werden alle in einem Programm zerstört, dessen Funktion main()keine automatischen Objekte enthält und den Aufruf von ausführt exit(). Die Kontrolle kann direkt auf eine solche übertragen werden, main()indem eine Ausnahme ausgelöst wird, die erfasst wird main().

struct exit_exception { 
   int c; 
   exit_exception(int c):c(c) { } 
};

int main() {
    try {
        // put all code in here
    } catch(exit_exception& e) {
        exit(e.c);
    }
}

Statt Aufruf exit(), ordnet diesen Code throw exit_exception(exit_code);stattdessen.


2
+1, weil Brian R. Bondy zwar gut war, Sie jedoch das Problem des Abbruchs / Exits (nicht des Destruktors der aufgerufenen Stapelobjekte) angesprochen und die Alternative für einen RAII-intensiven C ++ - Prozess angeboten haben.
Paercebal

Ich habe nach einer Möglichkeit gesucht, ein Programm zu beenden, ohne dtor anzurufen, und Ihre Antwort ist genau das, wonach ich gesucht habe! Danke
acemtp

Das ist natürlich völlig richtig, wenn es tatsächlich darauf ankommt, dass Ihre automatischen Objektzerstörer nicht aufgerufen werden :-)
Chris Huang-Leaver

Meines Wissens wäre ein weiterer Unterschied zwischen Exit und Abort, dass ein Abbruch (abhängig von der Betriebssystemkonfiguration) zur Erzeugung eines Core-Dumps führen könnte.
Dirk Herrmann

33

abort sendet ein SIGABRT-Signal, exit schließt nur die Anwendung, die eine normale Bereinigung durchführt.

Sie können ein Abbruchsignal nach Belieben verarbeiten. Standardmäßig wird die Anwendung jedoch auch mit einem Fehlercode geschlossen.

Abort führt keine Objektzerstörung Ihrer statischen und globalen Mitglieder durch, Exit jedoch.

Wenn die Anwendung vollständig geschlossen ist, gibt das Betriebssystem natürlich nicht freigegebenen Speicher und andere Ressourcen frei.

Sowohl bei Abbruch und Ausfahrt Programmabbruch (vorausgesetzt , Sie das Standardverhalten nicht außer Kraft setzen), wird der Return - Code an den übergeordneten Prozess zurückgeführt werden , die Ihre Anwendung gestartet.

Siehe folgendes Beispiel:

SomeClassType someobject;

void myProgramIsTerminating1(void)
{
  cout<<"exit function 1"<<endl;
}

void myProgramIsTerminating2(void)
{
  cout<<"exit function 2"<<endl;
}

int main(int argc, char**argv)
{
  atexit (myProgramIsTerminating1);
  atexit (myProgramIsTerminating2);
  //abort();
  return 0;
}

Bemerkungen:

  • Wenn der Abbruch nicht kommentiert ist, wird nichts gedruckt und der Destruktor eines Objekts wird nicht aufgerufen.

  • Wenn der Abbruch wie oben kommentiert wird: Ein Objektzerstörer wird aufgerufen, Sie erhalten die folgende Ausgabe:

Ausgangsfunktion 2
Ausgangsfunktion 1


Hier heißt es Exit-Funktion 2 DANN Exit-Funktion 1. gcc 4, Linux 2.6.
Strager

1
In der Manpage für atexit heißt es: "Funktionen [mit atexit registriert] werden in umgekehrter Reihenfolge aufgerufen; es werden keine Argumente übergeben."
Strager

@strager ist richtig, die von atexit registrierten Funktionen sollen in umgekehrter Reihenfolge aufgerufen werden, wenn entweder exit aufgerufen wird oder main zurückkehrt.
Robert Gamble

Es wurde ein Test ausgeführt, und es scheint, dass die Destruktoren für globale Instanzen nach allen atexit-Rückrufen aufgerufen werden.
Strager

+1, um die Leute daran zu erinnern, dass das Betriebssystem schließlich alle zugewiesenen Ressourcen auch nach einem abort () -Aufruf freigibt.
Fingolfin

10

Folgendes passiert, wenn ein Programm exit() aufruft :

  • Von der Funktion registrierte atexitFunktionen werden ausgeführt
  • Alle offenen Streams werden geleert und geschlossen, von erstellte Dateien tmpfilewerden entfernt
  • Das Programm wird mit dem angegebenen Exit-Code für den Host beendet

Die abortFunktion () sendet das SIGABRTSignal an den aktuellen Prozess. Wenn es nicht abgefangen wird, wird das Programm ohne Garantie beendet, dass offene Streams gelöscht / geschlossen werden oder dass temporäre Dateien, die über erstellt tmpfilewurden, entfernt werden, atexitregistrierte Funktionen nicht aufgerufen werden und eine Nicht-Funktion Der Exit-Status Null wird an den Host zurückgegeben.


hmm. Der Standard besagt, dass das Programm nur dann nicht beendet wird, wenn der Signalhandler "nicht zurückkehrt". Sie sind ziemlich gut mit C. Können Sie sich ein Szenario vorstellen, das es ermöglicht, die normale Ausführung fortzusetzen, ohne zurückzukehren? Ich stelle mir longjmp vor, bin mir aber nicht sicher, wie es sich in Signalhandlern verhält.
Johannes Schaub - litb

Im Allgemeinen ist das Aufrufen von longjmp von einem Signalhandler undefiniert, aber es gibt einen Sonderfall, wenn das Signal mit Raise / Abort generiert wurde. Ich denke, dies wäre theoretisch möglich, obwohl ich nicht glaube, dass ich es jemals gesehen habe. Jetzt muss ich es versuchen;)
Robert Gamble

1
Dies scheint zu funktionieren (aufgrund der Beschränkung auf 300 Zeichen in mehrere Posts unterteilt): #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> volatile sig_atomic_t do_abort = 1; jmp_buf env; void abort_handler (int i) {do_abort = 0; longjmp (env, 1);}
Robert Gamble

int main (void) {setjmp (env); setzt ("At setjmp"); if (do_abort) {signal (SIGABRT, abort_handler); setzt ("Abbruch aufrufen"); abbrechen(); } setzt ("Nicht abgebrochen!"); return 0; }
Robert Gamble

Unter Ubuntu 7.04 wird Folgendes gedruckt: Bei setjmp Abbruch aufrufen Bei setjmp Nicht abgebrochen!
Robert Gamble

5

Von der Handbuchseite exit ():

Die Funktion exit () bewirkt eine normale Prozessbeendigung und der Wert von Status & 0377 wird an das übergeordnete Element zurückgegeben.

Von der abort () Handbuchseite:

Mit abort () wird zuerst das SIGABRT-Signal entsperrt und dieses Signal dann für den aufrufenden Prozess ausgelöst. Dies führt zu einer abnormalen Beendigung des Prozesses, es sei denn, das SIGABRT-Signal wird abgefangen und der Signalhandler kehrt nicht zurück.


4

abortsendet das SIGABRTSignal. abortkehrt nicht zum Anrufer zurück. Der Standardhandler für das SIGABRTSignal schließt die Anwendung. stdioDateistreams werden geleert und dann geschlossen. Destruktoren für C ++ - Klasseninstanzen sind dies jedoch nicht (nicht sicher - vielleicht sind die Ergebnisse undefiniert?).

exithat seine eigenen Rückrufe, gesetzt mit atexit. Wenn Rückrufe angegeben werden (oder nur einer), werden sie in umgekehrter Reihenfolge wie ihre Registrierungsreihenfolge aufgerufen (wie ein Stapel), und das Programm wird beendet. Wie bei abort, exitkehrt nicht zum Anrufer zurück. stdioDateistreams werden geleert und dann geschlossen. Außerdem werden Destruktoren für C ++ - Klasseninstanzen aufgerufen.


Bei exit können mehrere Rückruffunktionen über atexit registriert werden. Wenn exit aufgerufen wird, werden alle Rückruffunktionen in der umgekehrten Reihenfolge aufgerufen, in der sie registriert wurden.
Robert Gamble

@Gamble, natürlich habe ich das selbst vor ein paar Minuten in einem Kommentar zu @ Bondys Antwort erwähnt. Ich werde meine eigene Antwort bearbeiten, um dies widerzuspiegeln.
Strager
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.