Question

Devrais-je utiliser les instructions exit () ou simplement renvoyer dans main () ? Personnellement, je préfère les instructions return car j’ai le sentiment que c’est comme si vous lisiez une autre fonction et que le contrôle de flux lorsque je lis le code est fluide (à mon avis). Et même si je veux refactoriser la fonction main () , avoir return semble être un meilleur choix que exit () .

Est-ce que exit () fait quelque chose de spécial que renvoie ne fait pas?

Était-ce utile?

La solution

En fait, il y a une différence, mais elle est subtile. Cela a plus d'implications pour C ++, mais les différences sont importantes.

Lorsque j'appelle return dans main () , les destructeurs sont appelés pour mes objets localement dimensionnés. Si j'appelle exit () , aucun destructeur ne sera appelé pour mes objets localement ciblés! Relisez-le. exit () ne renvoie pas . Cela signifie qu’une fois que j’appelle cela, il n’ya pas de "backsies". Tous les objets que vous avez créés dans cette fonction ne seront pas détruits. Souvent, cela n’a aucune implication, mais parfois, comme la fermeture de fichiers (vous voulez sûrement que toutes vos données soient vidées sur le disque?).

Notez que les objets static seront nettoyés même si vous appelez exit () . Notez enfin que si vous utilisez abort () , aucun objet ne sera détruit. C'est-à-dire qu'aucun objet global, aucun objet statique et aucun objet local n'aura son destructeur appelé.

Faites preuve de prudence lorsque vous privilégiez la sortie au retour.

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

Autres conseils

Une autre différence: exit est une bibliothèque standard fonction si vous avez besoin d'inclure en-têtes et lien avec la norme bibliothèque. Pour illustrer (en C ++), c'est un programme valide:

int main() { return 0; }

mais pour utiliser exit , vous aurez besoin d'un include:

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

De plus, cela ajoute une hypothèse supplémentaire: l'appel de exit à partir de main a les mêmes effets secondaires que celui de renvoyer zéro. Comme d'autres l'ont souligné, cela dépend du type d'exécutable que vous construisez (c'est-à-dire qui appelle main ). Codez-vous une application qui utilise le C-runtime? Un plugin Maya? Un service Windows? Un conducteur? Chaque cas nécessite des recherches pour voir si exit est équivalent à return . IMHO utilise exit lorsque vous entendez vraiment renvoyer rend le code encore plus confus. OTOH, si vous voulez vraiment dire exit , alors utilisez-le.

Il y a au moins une raison pour préférer exit : si l'un de vos gestionnaires atexit fait référence à des données de durée de stockage automatique dans main , ou si vous avez utilisé setvbuf ou setbuf pour attribuer à l'un des flux standard un tampon de durée de stockage automatique dans main , puis en revenant de main produit un comportement non défini, mais l'appel de exit est valide.

Une autre utilisation potentielle (généralement réservée aux programmes de jouets) est de quitter un programme avec des invocations récursives de main .

J'utilise toujours return car le prototype standard de main () indique qu'il renvoie un int .

Cela dit, certaines versions des normes accordent un traitement spécial à main et supposent qu’elle renvoie 0 s'il n'y a pas d'instruction return explicite. Étant donné le code suivant:

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

G ++ génère uniquement un avertissement pour foo () et ignore le retour manquant de main :

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

Je FORTEMENT d'appuyer le commentaire de R. sur l'utilisation de exit () afin d'éviter d'avoir la mémoire automatique stockée dans main () avant que le programme ne se termine réellement. Une instruction return X; dans main () n'est pas précisément équivalente à un appel à exit (X); , car le stockage dynamique de < code> main () disparaît lorsque main () revient, mais ne disparaît pas si un appel à exit () est effectué à la place.

De plus, en C ou dans un langage similaire à C, une instruction return indique clairement au lecteur que l'exécution se poursuivra dans la fonction appelante, et que cette poursuite est généralement techniquement vraie si vous comptez la routine de démarrage C qui a appelé votre fonction main () , ce n'est pas exactement ce que vous voulez dire quand vous voulez mettre fin au processus.

Après tout, si vous souhaitez terminer votre programme depuis une autre fonction que main () , vous devez appeler exit () . Faire cela de manière cohérente dans main () rend également votre code beaucoup plus lisible, et facilite beaucoup la redéfinition du code par quiconque. C'est-à-dire que le code copié de main () vers une autre fonction ne se comportera pas mal en raison d'instructions accidentelles return que devrait avoir été exit ( ) appelle.

Donc, en combinant tous ces points, la conclusion est que c’est une mauvaise habitude , au moins pour C, d’utiliser une instruction return pour terminer le programme dans < code> main () .

  

Est-ce que exit () fait quelque chose de spécial que 'return' ne fait pas?

Avec certains compilateurs pour plates-formes inhabituelles, exit () peut traduire son argument dans la valeur de sortie de votre programme, tandis qu'un retour de main () pourrait simplement passer directement la valeur à l'environnement hôte sans traduction.

La norme requiert un comportement identique dans ces cas (en particulier, elle indique que le renvoi de quelque chose qui est int - compatible avec main () doit être équivalent à l'appel de exit ( ) avec cette valeur). Le problème est que différents systèmes d’exploitation ont des conventions différentes pour interpréter les valeurs de sortie. Sur beaucoup de systèmes (BEAUCOUP!), 0 signifie succès et toute autre chose est un échec. Mais, disons, sur VMS, les valeurs impaires sont synonymes de succès et les plus équitables, d’échec. Si vous avez renvoyé 0 de main () , un utilisateur de VMS verrait un message désagréable concernant une violation d'accès. Il n’y avait pas réellement de violation d’accès - c’était simplement le message standard associé au code d’échec 0.

Ensuite, ANSI est arrivé et a béni EXIT_SUCCESS et EXIT_FAILURE en tant qu'arguments que vous pourriez transmettre à exit () . La norme indique également que exit (0) doit se comporter de manière identique à exit (EXIT_SUCCESS) , de sorte que la plupart des implémentations définissent EXIT_SUCCESS en 0 .

Par conséquent, le standard vous lie à VMS, car il ne laisse aucun moyen standard de renvoyer un code échec qui a la valeur 0.

Le compilateur C VAX / VMS C du début des années 90 n’a donc pas interprété la valeur renvoyée par main () , il a simplement renvoyé la valeur de l’environnement hôte. Mais si vous utilisiez exit () , il répondrait aux exigences de la norme: traduire EXIT_SUCCESS (ou 0 ) en code de succès et . EXIT_FAILURE en un code d’erreur générique. Pour utiliser EXIT_SUCCESS , vous deviez le transmettre à exit () , vous ne pouviez pas le renvoyer depuis main () . Je ne sais pas si des versions plus modernes de ce compilateur ont préservé ce comportement.

Un programme C portable ressemblait à ceci:

#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 */
}

De côté: si je me souviens bien, la convention VMS pour les valeurs de sortie est plus nuancée que celle de pair / impair En fait, il utilise quelque chose comme les trois bits inférieurs pour coder un niveau de gravité. De manière générale, toutefois, les niveaux de gravité impairs indiquaient le succès ou des informations diverses et les erreurs paires indiquaient des erreurs.

En C, le retour de main est identique à l'appel de exit avec la même valeur.

Section 5.1.2.2.3 du C norme déclare:

  

Si le type de retour de la fonction principale est un type compatible avec int   , un retour de l'appel initial à la fonction principale équivaut à   appeler la fonction de sortie avec la valeur renvoyée par le principal   fonctionne comme son argument ; 11) atteindre le} qui termine le   fonction principale renvoie la valeur 0. Si le type de retour est   non compatible avec int, le statut de fin est renvoyé à la   l'environnement hôte n'est pas spécifié.

Les règles pour C ++ sont un peu différentes, comme indiqué dans d'autres réponses.

Il existe en réalité une différence entre exit (0) et return (0) dans main & # 8211; & nbsp; lorsque votre < La fonction code> main est appelée plusieurs fois.

Le programme suivant

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

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

Exécuter en tant que

./program 0 0 0 0

Le résultat sera le suivant:

00000

Cependant celui-ci:

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

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

N'imprimera rien, quels que soient les arguments.

Si vous êtes certain que personne n'appellera explicitement votre main , ce n'est pas techniquement une grande différence en général, mais maintenir un code plus clair exit serait beaucoup mieux. Si, pour une raison quelconque, vous souhaitez appeler main & # 8211; vous devez l’adapter à vos besoins.

Parler de C.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top