Dois-je retourner EXIT_SUCCESS ou 0 depuis main ()?

124

C'est une question simple, mais je continue de voir des réponses contradictoires: la routine principale d'un programme C ++ doit-elle retourner 0ou EXIT_SUCCESS?

#include <cstdlib>
int main(){return EXIT_SUCCESS;}

ou

int main(){return 0;}

Sont-ils exactement la même chose? Ne doit EXIT_SUCCESSêtre utilisé qu'avec exit()?

Je pensais que ce EXIT_SUCCESSserait une meilleure option parce que d'autres logiciels peuvent vouloir considérer zéro comme un échec, mais j'ai également entendu dire que si vous revenez 0, le compilateur est capable de le changer de toute façon en une valeur différente.

Trevor Hickey
la source
Est-ce que cela répond à votre question? stackoverflow.com/questions/1188335/…
Blastfurnace
2
Cette réponse à propos de C90 paraphrase la norme - 0et EXIT_SUCCESSsont toutes deux interprétées comme un succès.
ta.speot.is
Je vais répondre ici car je pense que quelqu'un d'autre lira ceci à l'avenir. Fondamentalement, il existe de nombreux paradigmes sur ce à quoi ressemble le «C correct». Certains paradigmes préfèrent utiliser des littéraux plutôt que des macros, par exemple, au lieu de passer NULL comme argument, ils peuvent passer (const char *) 0 pour indiquer qu'il ne s'agit pas simplement d'un null, mais s'il n'était pas nul, ce devrait être un pointeur de caractère constant. D'autres paradigmes préfèrent être indépendants du type et en utilisant des types de macro, ils peuvent éviter d'avoir à changer leur base de code lorsque les choses changent radicalement. Par exemple, beaucoup -
Dmitry
@Dmitry <continued> Les définitions de type d'API Windows ne sont pas correctes dans les nouvelles plates-formes, mais comme il s'agissait de macros, elles avaient un moyen facile de changer tous les types en ceux qui fonctionnent en redéfinissant la macro, et la plupart de ces types sont simplement mis à l'échelle par définition (par exemple. int est différent sur différentes plates-formes). Pour résumer, utilisez des choses comme EXIT_SUCCESS si le code de retour est important et peut changer à l'avenir, sinon renvoyer 0 peut sembler un nombre magique, mais c'est toujours une convention standard parfaitement valide. le code d'erreur est principalement destiné aux programmes pour diriger les résultats du numéro de l'un à l'autre, -
Dmitry
@Dmitry <continued> utiliser des codes d'erreur pour déboguer votre programme est un peu faible car s'il retourne 0, ce sont des informations assez inutiles, sauf dans certains cas lorsqu'il y a des erreurs non gérées non gérées dans un programme qui peuvent faire en sorte que le programme s'arrête silencieusement, et vous avez besoin pour vérifier s'il a renvoyé normalement (0) ou si une erreur silencieuse s'est produite. Le numéro de retour est plus utile pour faire passer 0..255 d'un programme à un autre en fonction de leurs entrées, sinon il n'y a aucune raison d'y penser: soit retourner 0, soit utiliser un main précompilé qui intègre un appel vide "init" pour ne pas visuellement vous ennuyer avec un retour inutile.
Dmitry

Réponses:

151

EXIT_FAILURE, que ce soit dans une instruction return dans mainou en tant qu'argument de exit(), est le seul moyen portable d'indiquer l'échec d'un programme C ou C ++. exit(1)peut effectivement signaler une terminaison réussie sur VMS, par exemple.

Si vous prévoyez d'utiliser EXIT_FAILURElorsque votre programme échoue, alors vous pouvez aussi bien l'utiliser EXIT_SUCCESSlorsqu'il réussit, juste pour des raisons de symétrie.

D'un autre côté, si le programme ne signale jamais l'échec, vous pouvez utiliser soit 0ou EXIT_SUCCESS. Les deux sont garantis par la norme pour signaler la réussite. (Il est à peine possible que cela EXIT_SUCCESSpuisse avoir une valeur autre que 0, mais c'est égal à 0 sur chaque implémentation dont j'ai jamais entendu parler.)

L'utilisation 0a l'avantage mineur dont vous n'avez pas besoin #include <stdlib.h>en C, ou #include <cstdlib>en C ++ (si vous utilisez une returninstruction plutôt que d'appeler exit()) - mais pour un programme de toute taille significative, vous allez inclure stdlib directement ou indirectement en tous cas.

D'ailleurs, en C à partir du standard 1999, et dans toutes les versions de C ++, atteindre la fin de main()fait de return 0;toute façon un implicite , donc vous n'aurez peut-être pas besoin d'utiliser l'un 0ou l' autre ou EXIT_SUCCESSexplicitement. (Mais au moins en C, je considère qu'un return 0;style explicite est meilleur.)

(Quelqu'un a posé une question sur OpenVMS. Je ne l'ai pas utilisé depuis longtemps, mais si je me souviens bien, les valeurs d'état impaires indiquent généralement le succès tandis que les valeurs paires indiquent un échec. L'implémentation C correspond 0à 1, ce qui return 0;indique une fin réussie. Les autres valeurs sont transmises sans modification , donc return 1;indique également une fin réussie. EXIT_FAILUREaurait une valeur paire différente de zéro.)

Keith Thompson
la source
@KeithThompson pourriez-vous clarifier votre réponse en ce qui concerne VMS (OpenVMS?). Ce n'est pas clair la relation EXIT_SUCCESS / EXIT_FAILURE avec 0 et 1. J'expliquerais plutôt les valeurs impaires / paires.
malat
@malat: Utilisez-vous réellement VMS?
Keith Thompson
non, je ne l'ai jamais utilisé. Je cherchais une réponse canonique, car wikipedia utilisait une formulation différente .
malat
1
@Rhymoid: Ceci est spécifié par C, pas POSIX.
Keith Thompson
1
@DeanP: 0et EXIT_SUCCESSne sont pas garantis d'avoir la même valeur (je l'ai mentionné dans ma réponse), mais ils indiquent tous deux une résiliation réussie. EXIT_SUCCESSest stylistiquement meilleur si vous utilisez également EXIT_FAILURE, mais ça exit(0)va.
Keith Thompson
25

Ce n'est pas important. Les deux sont identiques.

Citations standard C ++:

Si la valeur de statut est zéro ou EXIT_SUCCESS, une forme définie par l'implémentation du statut de fin réussie est renvoyée.

Alok Save
la source
12
Cela n'a pas d'importance pour le compilateur, mais c'est peut-être une question de style.
celtschk
2
@celtschk: La question du style est basée sur la perception, c'est-à-dire non standardisé, donc cela ne compte pas comme une différence.Vous ne pouvez comparer que des pommes avec des pommes et non des pommes avec des poires.
Alok Save le
3
Il n'y a aucune garantie que EXIT_SUCCESS == 0. D'un autre côté, il n'y a aucune bonne raison pour que ce ne soit pas le cas.
Keith Thompson
@KeithThompson: pourquoi Il n'y a aucune garantie que EXIT_SUCCESS == 0.? Veuillez l'expliquer plus clairement.
Destructor
2
@PravasiMeet: Un système peut avoir plus d'une valeur indiquant le succès.
Keith Thompson
11

0 est, par définition, un nombre magique. EXIT_SUCCESS est presque universellement égal à 0, heureusement. Alors pourquoi ne pas simplement retourner / quitter 0?

exit (EXIT_SUCCESS); a un sens très clair.

sortie (0); d'autre part, est contre-intuitif à certains égards. Quelqu'un qui n'est pas familier avec le comportement du shell pourrait supposer que 0 == faux == mauvais, comme toute autre utilisation de 0 en C. Mais non - dans ce cas particulier, 0 == succès == bon. Pour les développeurs les plus expérimentés, cela ne posera pas de problème. Mais pourquoi trébucher le nouveau sans aucune raison?

tl; dr - s'il y a une constante définie pour votre nombre magique, il n'y a presque jamais de raison de ne pas utiliser la constante en premier lieu. C'est plus consultable, souvent plus clair, etc. et cela ne vous coûte rien.

James
la source
Je pense que vos commentaires sur les personnes qui s'attendent à ce que 0 soit automatiquement mauvais sont hors de propos. De très nombreuses API utilisent 0 pour le succès et non 0 pour l'échec, même dans stdlib. Par exemple , stdlib ( fclose(), setvbuf(), ...), (POSIX listen(), pthread_create(), pipe(), ...), et beaucoup, beaucoup d' autres bibliothèques (par exemple OpenGL [ glGetError()], zlib [ deflate()/ inflate()/ ...], SDL [ SDL_CreateWindowAndRenderer()/ ...], et plus).
Tim Čas
2
Bien sûr, il y a d'autres cas où 0 est utilisé pour «succès», mais il a raison sur le fait que cela prête à confusion.
Paul Wintz
10

C'est une histoire sans fin qui reflète les limites (un mythe) de "l'interopérabilité et la portabilité dans tous".

Ce que le programme doit renvoyer pour indiquer «succès» doit être défini par la personne qui reçoit la valeur (le système d'exploitation ou le processus qui a appelé le programme) et non par une spécification de langage.

Mais les programmeurs aiment écrire du code de manière "portable" et par conséquent ils inventent leur propre modèle pour le concept de "système d'exploitation" définissant les valeurs symboliques à renvoyer.

Maintenant, dans un scénario plusieurs-à-plusieurs (où de nombreux langages servent à écrire des programmes sur plusieurs systèmes), la correspondance entre la convention de langage pour «succès» et celle du système d'exploitation (que personne ne peut accorder à être toujours la même) devrait être géré par l'implémentation spécifique d'une bibliothèque pour une plate-forme cible spécifique.

Mais - malheureusement - ces concepts n'étaient pas aussi clairs au moment où le langage C a été déployé (principalement pour écrire le noyau UNIX), et les Gigagrammes de livres où écrits en disant "retour 0 signifie succès", puisque c'était vrai sur le système d'exploitation à cette fois avoir un compilateur C.

Dès lors, aucune normalisation claire n'a jamais été faite sur la manière dont une telle correspondance devrait être traitée. C et C ++ ont leur propre définition des «valeurs de retour» mais personne n'accorde une traduction correcte du système d'exploitation (ou mieux: aucune documentation du compilateur n'en dit rien). 0 signifie succès si vrai pour UNIX - LINUX et - pour des raisons indépendantes - pour Windows également, et cela couvre 90% des "ordinateurs grand public" existants, qui - dans la plupart des cas - ne tiennent pas compte de la valeur de retour (nous pouvons donc discutez pendant des décennies, mais personne ne le remarquera jamais!)

Dans ce scénario, avant de prendre une décision, posez les questions suivantes: - Suis-je intéressé à communiquer quelque chose à mon interlocuteur sur mon existant? (Si je retourne toujours 0 ... il n'y a aucun indice derrière tout) - Mon interlocuteur a-t-il des conventions sur cette communication? (Notez qu'une seule valeur n'est pas une convention: cela ne permet aucune représentation d'information)

Si les deux réponses sont non, la bonne solution est probablement de ne pas écrire du tout l'instruction de retour principale. (Et laissez le compilateur décider, en ce qui concerne la cible).

Si aucune convention n'est en place 0 = le succès satisfait la plupart des situations (et l'utilisation de symboles peut être problématique, s'ils introduisent une convention).

Si des conventions sont en place, veillez à utiliser des constantes symboliques qui sont cohérentes avec elles (et assurez la cohérence des conventions, et non la cohérence des valeurs, entre les plates-formes).

Emilio Garavaglia
la source
4

Une fois que vous commencez à écrire du code qui peut renvoyer une myriade d'états de sortie, vous commencez à #definetous. Dans ce cas, EXIT_SUCCESScela a du sens dans le contexte de ne pas être un " nombre magique ". Cela rend votre code plus lisible car tous les autres codes de sortie le seront EXIT_SOMETHING. Si vous écrivez simplement un programme qui reviendra une fois terminé, il return 0est valide et probablement même plus propre car cela suggère qu'il n'y a pas de structure de code de retour sophistiquée.

Phonon
la source
0

Ce que vous revenez d'un programme n'est qu'une convention.

Non, je ne peux penser à aucune circonstance où "EXIT_SUCCESS" ne serait pas "0".

Personnellement, je recommanderais "0".

A MON HUMBLE AVIS...

paulsm4
la source
1
Je programme du C ++ depuis 10 ans et je ne me souviens toujours pas si 0 signifie un succès ou un échec en termes de valeurs de retour.
lahjaton_j
@lahjaton_j Je comprends. Il pense que c'est parce que c'est contre-intuitif: 0c'est faux, et de nombreuses fonctions retournent 0en cas d'échec / ne rien faire.
sens-questions
-5

Certains compilateurs pourraient créer des problèmes avec cela - sur un compilateur Mac C ++, EXIT_SUCCESS fonctionnait bien pour moi, mais sur un complicateur Linux C ++, j'ai dû ajouter cstdlib pour qu'il sache ce qu'est EXIT_SUCCESS. À part cela, ils sont identiques.

Ambidextre
la source
Je voulais dire sur un Mac EXIT_SUCCESS fonctionnait sans inclure cstdlib.
Ambidextre
4
Si EXIT_SUCCESStravaillé sans inclure ni <stdlib.h>ni <cstdlib>, un autre en-tête doit l'avoir défini, directement ou indirectement. En C ++, il est courant pour les en-têtes standard vers d' #includeautres en-têtes standard. Si cela se compile sans erreur: int main() { return EXIT_SUCCESS; }alors votre compilateur est probablement bogué.
Keith Thompson