Quelle est la différence entre exit () et abort ()?

130

En C et C ++, quelle est la différence entre exit()et abort()? J'essaye de terminer mon programme après une erreur (pas une exception).

Martin Liversage
la source

Réponses:

116

abort()quitte votre programme sans appeler les fonctions enregistrées en utilisant d' atexit()abord, et sans appeler d'abord les destructeurs d'objets. exit()fait les deux avant de quitter votre programme. Cependant, il n'appelle pas de destructeurs pour les objets automatiques. Alors

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

Détruira aet bcorrectement, mais n'appellera pas les destructeurs de c. abort()n'appellerait pas les destructeurs de l'un ou l'autre des objets. Comme cela est malheureux, la norme C ++ décrit un mécanisme alternatif qui garantit une terminaison correcte:

Les objets avec une durée de stockage automatique sont tous détruits dans un programme dont la fonction main()ne contient aucun objet automatique et exécute l'appel à exit(). Le contrôle peut être transféré directement à un tel main()en lançant une exception interceptée 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);
    }
}

Au lieu d'appeler exit(), organisez ce code à la throw exit_exception(exit_code);place.

Johannes Schaub - litb
la source
2
+1 parce que, alors que Brian R. Bondy était bon, vous avez soulevé le problème de l'abandon / sortie (pas le destructeur des objets de pile appelés), et offert l'alternative pour un processus C ++ intensif en RAII.
paercebal
Je cherchais un moyen de quitter un programme sans appeler dtor et votre réponse est exactement ce que je cherchais! Merci
acemtp
C'est parfaitement correct bien sûr, s'il est vraiment important que vos destructeurs automatiques d'objets ne soient pas appelés :-)
Chris Huang-Leaver
À ma connaissance, une autre différence entre la sortie et l'abandon serait que l'abandon pourrait (selon la configuration du système d'exploitation) conduire à la génération d'un vidage de mémoire.
Dirk Herrmann le
33

abort envoie un signal SIGABRT, exit ferme simplement l'application effectuant un nettoyage normal.

Vous pouvez gérer un signal d' abandon comme vous le souhaitez, mais le comportement par défaut consiste également à fermer l'application avec un code d'erreur.

abort n'effectuera pas la destruction d'objets de vos membres statiques et globaux, mais exit le fera.

Bien sûr, lorsque l'application est complètement fermée, le système d'exploitation libère toute mémoire non libérée et d'autres ressources.

À la fois lors de l'arrêt du programme d' abandon et de sortie (en supposant que vous n'ayez pas remplacé le comportement par défaut), le code de retour sera renvoyé au processus parent qui a démarré votre application.

Consultez l'exemple suivant:

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;
}

Commentaires:

  • Si abort est décommentée: rien est imprimé et le destructeur de SomeObject ne sera pas appelé.

  • Si abandonner est commenté comme ci-dessus: un destructeur d'objet sera appelé, vous obtiendrez la sortie suivante:

sortie fonction 2
sortie fonction 1

Brian R. Bondy
la source
Ici, il a appelé la fonction de sortie 2 PUIS la fonction de sortie 1. gcc 4, Linux 2.6.
strager
1
La page de manuel pour atexit dit: "Les fonctions [enregistrées en utilisant atexit] sont appelées dans l'ordre inverse; aucun argument n'est passé."
strager
@strager a raison, les fonctions enregistrées par atexit sont censées être appelées dans l'ordre inverse lorsque l'exit est appelé ou le retour principal.
Robert Gamble
A effectué un test et il semble que les destructeurs d'instances globales soient appelés après tous les rappels atexit.
strager
+1 pour rappeler aux gens que le système d'exploitation finira par libérer toutes les ressources allouées même après un appel abort ().
Fingolfin
10

Les choses suivantes se produisent lorsqu'un programme appelle exit():

  • Les fonctions enregistrées par la atexitfonction sont exécutées
  • Tous les flux ouverts sont vidés et fermés, les fichiers créés par tmpfilesont supprimés
  • Le programme se termine avec le code de sortie spécifié pour l'hôte

La abortfonction () envoie le SIGABRTsignal au processus en cours, s'il n'est pas intercepté, le programme se termine sans aucune garantie que les flux ouverts sont vidés / fermés ou que les fichiers temporaires créés via tmpfilesont supprimés, atexitles fonctions enregistrées ne sont pas appelées et un non- l'état de sortie zéro est renvoyé à l'hôte.

Robert Gamble
la source
hmm. la norme dit que le programme n'est pas terminé uniquement si le gestionnaire de signaux "ne retourne pas". vous êtes plutôt bien avec C. pouvez-vous imaginer un scénario qui permettrait de continuer l'exécution normale sans revenir? J'imagine longjmp, mais je ne sais pas comment il se comporte dans les gestionnaires de signaux.
Johannes Schaub - litb
En général, appeler longjmp à partir d'un gestionnaire de signaux n'est pas défini, mais il existe un cas particulier lorsque le signal a été généré avec augmentation / annulation, donc je suppose que cela serait théoriquement possible bien que je ne pense pas l'avoir jamais vu faire. Maintenant, je vais devoir l'essayer;)
Robert Gamble
1
Cela semble fonctionner (divisé en plusieurs messages en raison de la limite de 300 caractères): #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); met ("At setjmp"); if (do_abort) {signal (SIGABRT, abort_handler); met ("Appel abandonné"); avorter(); } met ("N'a pas abandonné!"); return 0; }
Robert Gamble
Sur Ubuntu 7.04, ceci affiche: At setjmp Appel abandonné At setjmp N'a pas abandonné!
Robert Gamble
5

Depuis la page de manuel exit ():

La fonction exit () provoque l'arrêt normal du processus et la valeur de status & 0377 est renvoyée au parent.

Depuis la page de manuel abort ():

L'abort () débloque d'abord le signal SIGABRT, puis lève ce signal pour le processus appelant. Cela entraîne l'arrêt anormal du processus à moins que le signal SIGABRT ne soit capturé et que le gestionnaire de signaux ne retourne pas.

Federico A. Ramponi
la source
4

abortenvoie le SIGABRTsignal. abortne revient pas à l'appelant. Le gestionnaire par défaut du SIGABRTsignal ferme l'application. stdioles flux de fichiers sont vidés, puis fermés. Cependant, les destructeurs pour les instances de classe C ++ ne le sont pas (pas sûr sur celui-ci - peut-être que les résultats ne sont pas définis?).

exita ses propres rappels, définis avec atexit. Si des callbacks sont spécifiés (ou un seul), ils sont appelés dans l'ordre inverse de leur ordre d'enregistrement (comme une pile), puis le programme se termine. Comme avec abort, exitne revient pas à l'appelant. stdioles flux de fichiers sont vidés, puis fermés. En outre, les destructeurs pour les instances de classe C ++ sont appelés.

strager
la source
exit peut avoir plusieurs fonctions de rappel enregistrées via atexit, lorsque exit est appelé toutes les fonctions de rappel seront appelées dans l'ordre inverse dans lequel elles ont été enregistrées.
Robert Gamble
@Gamble, bien sûr, je l'ai mentionné moi-même il y a quelques minutes dans un commentaire à la réponse de @ Bondy. Je vais modifier ma propre réponse pour refléter cela.
strager