En fait, il y a une différence, mais c'est subtil. Il a plus d'implications pour C ++, mais les différences sont importantes.
Quand j'appelle return
à main()
, Destructeurs seront appelés à mes objets scope localement. Si j'appelle exit()
, aucun destructeur ne sera appelé pour mes objets de portée locale! Relisez ça. exit()
ne revient pas . Cela signifie qu'une fois que je l'appelle, il n'y a «aucun backsies». 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 static
objets 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'auront leurs destructeurs appelés.
Procédez avec prudence lorsque vous privilégiez la sortie au retour.
http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a
thread_local
les destructeurs d'objets seront appelés. Les destructeurs d'autres objets locaux ne sont toujours pas appelés. ideone.com/Y6Dh3fexit()
fermeture des fichiers proprement est en fait faux. Le seul moment où les données peuvent ne pas être vidées est dans le cas contraire: c'est-à-dire si l'on utilisereturn
depuismain()
et que l'on a appelésetbuf()
ousetvbuf()
avec un tampon déclaré comme stockage automatique dansmain()
(comme expliqué dans la réponse de R. ci-dessous). C'est vraiment dommage que cette question soit balisée avec C et C ++ (et avec le style de codage - ce n'est pas un problème de style!).Une autre différence:
exit
c'est une fonction de bibliothèque standard, vous devez donc inclure des en-têtes et un lien avec la bibliothèque standard. Pour illustrer (en C ++), ceci est un programme valide:mais pour l'utiliser,
exit
vous aurez besoin d'un include:De plus, cela ajoute une hypothèse supplémentaire: que l'appel
exit
demain
a les mêmes effets secondaires que le retour à zéro. Comme d'autres l'ont souligné, cela dépend du type d'exécutable que vous créez (c'est-à-dire qui appellemain
). Codez-vous une application qui utilise le C-runtime? Un plugin Maya? Un service Windows? Un chauffeur? Chaque cas nécessitera des recherches pour voir siexit
est équivalent àreturn
. Àexit
mon humble avis, utiliser quand vous voulez vraiment direreturn
rend le code plus confus. OTOH, si vous voulez vraiment direexit
, alors utilisez-le par tous les moyens.la source
Il y a au moins une raison de préférer
exit
: si l'un de vosatexit
gestionnaires fait référence à des données de durée de stockage automatique dansmain
, ou si vous avez utilisésetvbuf
ousetbuf
pour affecter à l'un des flux standard un tampon de durée de stockage automatique dansmain
, puis le retour demain
produit comportement indéfini, mais l'appelexit
est valide.Une autre utilisation potentielle (généralement réservée aux programmes de jouets, cependant) est de quitter un programme avec des invocations récursives de
main
.la source
main()
- c'est juste une fonction comme les autres. D'un autre côté, puisqu'il a une mention spéciale dans la norme, la norme doit faire assez attention à la façon dont elle la définitmain()
et aux choses qui lui sont chères et proches. Cependant, en fin de compte, bien que la norme n'exige pas (et ne doit pas obliger) les compilateurs à faire quelque chose de spécial concernant le stockage automatique dansmain()
. Veuillez prendre soin de lire la note de bas de page # 11 sous le paragraphe auquel vous avez fait référence dans votre commentaire.J'utilise toujours
return
parce que le prototype standard pourmain()
dit qu'il retourne unint
.Cela dit, certaines versions des normes accordent
main
un traitement spécial et supposent qu'elle renvoie 0 s'il n'y a pas dereturn
déclaration explicite . Étant donné le code suivant:G ++ génère uniquement un avertissement pour
foo()
et ignore le retour manquant demain
:la source
return
pour mettre fin à son exécution. L'appelexit()
est également un moyen valide, et parfois nécessaire, de mettre fin à l'exécution d'une fonction. En effet, comme moi et d'autres l'ont décrit ailleurs, appelerexit()
même demain()
transmet une intention beaucoup plus claire de quitter l'intégralité du processus, préserve le stockage automatique jusqu'à la fin du processus et facilite la maintenance lors de la refactorisation future du code. C en utilisantreturn
dansmain()
lorsque l'intention est de mettre fin au processus est donc sans doute une mauvaise pratique.Je FORTEMENT deuxième le commentaire par R. sur l' utilisation de la sortie () afin d'éviter le stockage automatique
main()
remis en état avant le programme en fait se termine. Unereturn X;
instruction inmain()
n'est pas exactement équivalente à un appel àexit(X);
, car le stockage dynamique demain()
disparaît lors dumain()
retour, mais il ne disparaît pas si un appel àexit()
est effectué à la place.De plus, en C ou tout autre langage de type C, une
return
instruction indique fortement au lecteur que l'exécution se poursuivra dans la fonction appelante, et bien que cette poursuite de l'exécution soit généralement techniquement vraie si vous comptez la routine de démarrage C qui a appelé votremain()
fonction, ce n'est pas exactement ce que vous voulez dire lorsque vous voulez mettre fin au processus.Après tout, si vous souhaitez terminer votre programme à partir de toute autre fonction, sauf que
main()
vous devez appelerexit()
. Le faire de manière cohérentemain()
rend également votre code beaucoup plus lisible, et il est également beaucoup plus facile pour quiconque de re-factoriser votre code; c'est-à-dire que le code copié depuismain()
une autre fonction ne se comportera pas mal en raison dereturn
déclarations accidentelles qui auraient dû être desexit()
appels.Donc, en combinant tous ces points ensemble, la conclusion est que c'est une mauvaise habitude , au moins pour C, d'utiliser une
return
déclaration pour terminer le programmemain()
.la source
exit()
en général, mais utilisez-le si unethrow
ou desabort()
alternatives ne fonctionnent pas dans un contexte spécifique. Mais surtout évitezexit()
en principal, et utilisez plutôt le retour en principal comme pratique typique.Avec certains compilateurs pour les plates-formes inhabituelles,
exit()
pourrait traduire son argument en valeur de sortie de votre programme tandis qu'un retour demain()
pourrait simplement passer la valeur directement à l'environnement hôte sans aucune traduction.La norme requiert un comportement identique dans ces cas (en particulier, elle indique que renvoyer quelque chose qui est
int
compatible à partir demain()
devrait être équivalent à appelerexit()
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 de nombreux systèmes (BEAUCOUP!), 0 signifie succès et tout le reste est un échec. Mais sur, par exemple, VMS, les valeurs impaires signifient le succès et même les valeurs signifient l'échec. Si vous renvoyiez 0 demain()
, un utilisateur VMS verrait un méchant message 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.Puis l'ANSI est venu et a béni
EXIT_SUCCESS
etEXIT_FAILURE
comme arguments vous pourriez passerexit()
. La norme indique également queexit(0)
devrait comporter de manière identique àexit(EXIT_SUCCESS)
, de sorte que la plupart des implémentations définissentEXIT_SUCCESS
à0
.La norme, par conséquent, vous met dans une liaison sur VMS, car elle ne laisse aucun moyen standard de renvoyer un code d' échec qui se trouve avoir la valeur 0.
Le compilateur VAX / VMS C de l'ère du début des années 1990 n'a donc pas interprété la valeur de retour
main()
, il a simplement renvoyé toute valeur à l'environnement hôte. Mais si vous avez utiliséexit()
il ferait ce que la norme exigeait: traduireEXIT_SUCCESS
(ou0
) en un code de réussite etEXIT_FAILURE
en un code d'échec générique. Pour utiliserEXIT_SUCCESS
, vous deviez passer àexit()
, on ne pouvait pas retourner à partirmain()
. Je ne sais pas si des versions plus modernes de ce compilateur ont préservé ce comportement.Un programme C portable ressemblait à ceci:
En plus: Si je me souviens bien, la convention VMS pour les valeurs de sortie est plus nuancée qu'impaire / paire. Il utilise en fait quelque chose comme les trois bits bas pour coder un niveau de gravité. D'une manière générale, cependant, les niveaux de gravité impairs indiquaient le succès ou des informations diverses et les pairs même indiquaient des erreurs.
la source
returned
parmain
différente de la valeur passéeexit
- mais la norme dit expressément: « Si le type de retour de lamain
fonction est un type compatible avecint
un retour de l'appel initial à lamain
fonction est équivaut à appeler laexit
fonction avec la valeur renvoyée par lamain
fonction comme argument ". C'est C11; C89 / C90 avait presque le même libellé.EXIT_SUCCESS
, il n'y avait aucun moyen de renvoyer un état d' échec spécifique à la plate-forme avec la valeur 0, ce qui peut être la raison pour laquelle certains des compilateurs de l'époque traitaient le retour de la main etexit()
différemment.En C, le retour
main
est exactement le même que l'appelexit
avec la même valeur.La section 5.1.2.2.3 de la norme C stipule:
Les règles pour C ++ sont un peu différentes comme mentionné dans d'autres réponses.
la source
Il y a en fait une différence entre
exit(0)
etreturn(0)
inmain
- lorsque votremain
fonction est appelée plusieurs fois.Le programme suivant
Courir comme
Se traduira par la sortie suivante:
Cependant celui-ci:
N'imprime rien, quels que soient les arguments.
Si vous êtes sûr que personne n'appellera jamais votre
main
explicitement, ce n'est pas techniquement une grande différence en général, mais conserver un code plus clairexit
serait beaucoup mieux. Si, pour une raison quelconque, vous souhaitez appelermain
, vous devez l'adapter à vos besoins.En parlant de C.
la source