Que doit retourner main () en C et C ++?

695

Quelle est la manière correcte (la plus efficace) de définir la main()fonction en C et C ++ - int main()ou void main()- et pourquoi? Si int main()alors return 1ou return 0?


Il existe de nombreux doublons de cette question, notamment:

En relation:

Joel
la source
28
Je pense toujours que c'est assez vague aussi. Définissez «le plus efficace» pour moi. Efficace dans quel sens? Dans le sens de prendre moins de mémoire? Dans le sens de courir plus vite? Je peux voir les réponses utiles, mais je pense toujours que la question est formulée assez mal.
Onorio Catenacci
7
Pish chic, le contexte de l'efficacité est ici évident, en particulier avec les exemples (qui sont probablement là pour clarifier la définition de «efficace»). Espérons que le mauvais tampon ne se soit pas glissé dans un trou et regrette entièrement la question. On pourrait dire que, indépendamment de void ou int, une valeur est retournée, elle n'a donc aucun impact sur la taille du fichier, les opérations exécutées ni la mémoire allouée. Et les gens, dans la plupart des systèmes d'exploitation, ont tendance à retourner 0 en cas de succès, et quelque chose d'autre en cas de succès ou d'échec, mais il n'y a pas de norme. En fin de compte, aucune différence d'efficacité d'une manière évidente.
Kit10
"correct (le plus efficace)" n'a pas de sens. Efficace est une chose, correct en est une autre. mainest appelé une fois (et en C ++ ne peut être appelé qu'une seule fois: pas de récursivité). Si vous ne voulez pas que l'exécution passe beaucoup de temps main, n'invoquez pas le programme un grand nombre de fois: faites en sorte que le programme implémente la répétition.
Kaz
2
Je trouve intéressant qu'aucune des réponses, pour autant que je sache, ne fournit un exemple pleinement fonctionnel, y compris les #includedéclarations
puk
3
Les valeurs de retour n'ont aucun sens sur une plate-forme sans système d'exploitation. Vous ne revenez à rien. Si vous frappez un returndans main(...)sur un appareil embarqué, votre système passe dans un état imprévisible et votre machine à laver deviendra conscient de soi et essayer de vous tuer. Donc, nous utilisons void main()dans ce cas. Il s'agit d'une pratique standard dans le secteur du métal nu embarqué.
3Dave

Réponses:

570

La valeur de retour pour mainindique comment le programme s'est arrêté. La sortie normale est représentée par une valeur de retour 0 de main. Une sortie anormale est signalée par un retour non nul, mais il n'y a pas de norme pour la façon dont les codes non nuls sont interprétés. Comme indiqué par d'autres, void main()est interdit par la norme C ++ et ne doit pas être utilisé. Les mainsignatures C ++ valides sont:

int main()

et

int main(int argc, char* argv[])

ce qui équivaut à

int main(int argc, char** argv)

Il convient également de noter qu'en C ++, il int main()peut être laissé sans instruction de retour, auquel cas il renvoie par défaut 0. Cela est également vrai avec un programme C99. Que ce return 0;soit omis ou non est sujet à débat. La plage de signatures principales valides du programme C est beaucoup plus grande.

L'efficacité n'est pas un problème avec la mainfonction. Il ne peut être entré et laissé qu'une seule fois (marquant le début et la fin du programme) selon la norme C ++. Pour C, la rentrée main()est autorisée, mais doit être évitée.

workmad3
la source
69
principal peut être entré / quitté plusieurs fois, mais ce programme ne gagnera probablement pas de prix de design;)
korona
13
C99 a également la mauvaise caractéristique C ++ qui atteint la fin de la fonction main () équivaut à retourner 0 - si main () est défini pour retourner un type compatible avec int (section 5.1.2.2.3).
Jonathan Leffler
62
rentrer principal n'est pas valide en C ++. De manière explicite dans la norme, 3.6.1.3 stipule que "main ne doit pas être utilisé dans un programme"
workmad3
117
stdlib.h fournit EXIT_SUCCESS et EXIT_FAILURE à cet effet
Clay
20
0 et non nul sont corrects mais n'ont aucun sens pour quelqu'un qui lit votre code. Cette question est la preuve que les gens ne savent pas ce que sont les codes valides / invalides. EXIT_SUCCESS / EXIT_FAILURE sont beaucoup plus clairs.
JaredPar
169

La réponse acceptée semble être ciblée pour C ++, j'ai donc pensé ajouter une réponse qui concerne C, et cela diffère de plusieurs façons.

ISO / CEI 9899: 1989 (C90):

main() doit être déclaré comme suit:

int main(void)
int main(int argc, char **argv)

Ou équivalent. Par exemple, int main(int argc, char *argv[])est équivalent au second. En outre, le inttype de retour peut être omis car il s'agit d'une valeur par défaut.

Si une implémentation le permet, elle main()peut être déclarée par d'autres moyens, mais cela rend l'implémentation du programme définie et non plus strictement conforme.

La norme définit 3 valeurs pour le retour qui sont strictement conformes (c'est-à-dire, ne reposent pas sur un comportement défini par l'implémentation): 0et EXIT_SUCCESSpour une terminaison réussie et EXIT_FAILUREpour une terminaison infructueuse. Toutes les autres valeurs sont non standard et définies par l'implémentation. main()doit avoir une returndéclaration explicite à la fin pour éviter un comportement indéfini.

Enfin, il n'y a rien de mal du point de vue des normes à appeler à main()partir d'un programme.

ISO / CEI 9899: 1999 (C99):

Pour C99, tout est le même que ci-dessus sauf:

  • Le inttype de retour ne doit pas être omis.
  • Vous pouvez omettre la déclaration de retour de main(). Si vous le faites et que vous avez main()terminé, il y a un implicite return 0.
Chris Young
la source
1
@Lundin Je ne pense pas que vous ayez besoin d'une citation pour dire que quelqu'un est autorisé à créer un compilateur qui accepte des programmes non conformes aux normes, ou à avoir un compilateur non conforme aux normes. C'est la connaissance commune et le bon sens
KABoissonneault
4
@KABoissonneault Le comportement défini par l'implémentation est un terme de la norme, par opposition à un comportement complètement non documenté. Si vous implémentez quelque chose qui est répertorié comme comportement défini par l'implémentation, vous suivez toujours la norme. Dans ce cas, C89, qui a été cité, ne répertorie aucun comportement défini par l'implémentation, d'où la nécessité de citer, pour prouver qu'il ne fait pas que créer les choses à l'improviste.
Lundin
1
@Lundin Vous voyez cela dans le mauvais sens. Ce dont nous parlons n'est pas un comportement défini par l'implémentation, nous parlons d'une implémentation s'écartant de la norme s'ils le souhaitent. Cela ressemble plus à un enfant désobéissant à ses parents: vous n'avez pas besoin d'un devis des parents pour vous dire de quelle manière un enfant peut aller à l'encontre de ce que les parents ont dit. Vous savez juste que dès que l'enfant choisit de le faire, il ne se conforme plus aux lignes
directrices de
2
@KABoissonneault La partie que j'ai citée dans mon commentaire concerne définitivement le comportement défini par l'implémentation (par opposition aux extensions de compilateur non standard .) Je parle donc de comportement défini par l'implémentation. Si vous avez un monologue sur autre chose, bonne chance avec ça.
Lundin
1
@Lundin Je suppose que le libellé de la citation est déroutant (la partie où ils disent "mais cela rend la mise en œuvre du programme définie") mais je suis presque sûr que la personne parlait d'un comportement non standard (comme dit dans "Si une mise en œuvre le permet "et" et n'est plus strictement conforme [à la norme] ") par opposition au comportement réel défini par l'implémentation. La personne devrait certainement reformuler sa réponse, mais je ne pense toujours pas qu'une citation de la norme soit nécessaire à ce sujet
KABoissonneault
117

Standard C - Environnement hébergé

Pour un environnement hébergé (c'est le normal), la norme C11 (ISO / IEC 9899: 2011) dit:

5.1.2.2.1 Démarrage du programme

La fonction appelée au démarrage du programme est nommée main . L'implémentation ne déclare aucun prototype pour cette fonction. Il doit être défini avec un type de retour intet sans paramètres:

int main(void) { /* ... */ }

ou avec deux paramètres (appelés ici argcetargv , bien que tous les noms puissent être utilisés, car ils sont locaux à la fonction dans laquelle ils sont déclarés):

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

ou équivalent;10) ou d'une autre manière définie par la mise en œuvre.

S'ils sont déclarés, les paramètres de la fonction principale doivent respecter les contraintes suivantes:

  • La valeur de argc doit être non négative.
  • argv[argc] doit être un pointeur nul.
  • Si la valeur de argcest supérieure à zéro, les membres du tableau argv[0]via argv[argc-1] inclus doivent contenir des pointeurs vers des chaînes, qui reçoivent des valeurs définies par l'implémentation par l'environnement hôte avant le démarrage du programme. L'intention est de fournir au programme des informations déterminées avant le démarrage du programme depuis un autre endroit de l'environnement hébergé. Si l'environnement hôte n'est pas capable de fournir des chaînes avec des lettres en majuscules et en minuscules, la mise en œuvre doit garantir que les chaînes sont reçues en minuscules.
  • Si la valeur de argcest supérieure à zéro, la chaîne pointée par argv[0] représente le nom du programme; argv[0][0]doit être le caractère nul si le nom du programme n'est pas disponible dans l'environnement hôte. Si la valeur de argcest supérieure à un, les chaînes pointées par à argv[1]travers argv[argc-1] représentent les paramètres du programme.
  • Les paramètres argcet argvles chaînes pointés par le argvtableau doivent être modifiables par le programme et conserver leurs dernières valeurs stockées entre le démarrage du programme et la fin du programme.

10) Ainsi, intpeut être remplacé par un nom typedef défini comme int, ou le type de argvpeut être écrit comme char **argv, et ainsi de suite.

Fin du programme en C99 ou C11

La valeur renvoyée par main()est transmise à «l'environnement» d'une manière définie par l'implémentation.

5.1.2.2.3 Fin du programme

1 Si le type de retour de la mainfonction est compatible avec un type int, un retour de l'appel initial à la mainfonction équivaut à appeler la exitfonction avec la valeur renvoyée par la mainfonction comme argument; 11) atteindre la }fin de la mainfonction renvoie une valeur de 0. Si le type de retour n'est pas compatible avec int, l'état de terminaison renvoyé à l'environnement hôte n'est pas spécifié.

11) Conformément au 6.2.4, les durées de vie des objets avec durée de stockage automatique déclarée en main seront terminées dans le premier cas, même si elles ne le seraient pas dans le second.

Notez que 0c'est obligatoire comme «succès». Vous pouvez utiliser EXIT_FAILUREet à EXIT_SUCCESSpartir de <stdlib.h>si vous préférez, mais 0 est bien établi, ainsi que 1. Voir aussi Codes de sortie supérieurs à 255 - possible? .

Dans C89 (et donc dans Microsoft C), il n'y a aucune déclaration sur ce qui se passe si la main()fonction retourne mais ne spécifie pas de valeur de retour; il conduit donc à un comportement indéfini.

7.22.4.4 La exitfonction

¶5 Enfin, le contrôle est retourné à l'environnement hôte. Si la valeur de statusest zéro ou EXIT_SUCCESS, une forme définie par l'implémentation de la terminaison réussie du statut est renvoyée. Si la valeur de statusest EXIT_FAILURE, une forme définie par l'implémentation de la terminaison d'échec d' état est renvoyée. Sinon, le statut renvoyé est défini par l'implémentation.

Standard C ++ - Environnement hébergé

La norme C ++ 11 (ISO / IEC 14882: 2011) dit:

3.6.1 Fonction principale [basic.start.main]

¶1 Un programme doit contenir une fonction globale appelée main, qui est le début désigné du programme. [...]

¶2 Une implémentation ne doit pas prédéfinir la fonction principale. Cette fonction ne doit pas être surchargée. Il doit avoir un type de retour de type int, mais sinon son type est défini par l'implémentation. Toutes les implémentations doivent permettre les deux définitions suivantes de main:

int main() { /* ... */ }

et

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

Dans cette dernière forme argcdoit être le nombre d'arguments transmis au programme à partir de l'environnement dans lequel le programme est exécuté. Si argcest différent de zéro, ces arguments doivent être fournis par le argv[0] biais argv[argc-1]de pointeurs vers les caractères initiaux des chaînes multioctets à terminaison nulle (NTMBS) (17.5.2.1.4.2) et argv[0]doivent être le pointeur sur le caractère initial d'un NTMBS qui représente le nom utilisé pour appeler le programme ou "". La valeur de argcdoit être non négative. La valeur de argv[argc] doit être 0. [Remarque: Il est recommandé d'ajouter tout autre paramètre (facultatif) après argv. —Fin note]

¶3 La fonction mainne doit pas être utilisée dans un programme. La liaison (3.5) de mainest définie par l'implémentation. [...]

¶5 Une instruction return dans main a pour effet de quitter la fonction main (détruire tous les objets avec une durée de stockage automatique) et d'appeler std::exitavec la valeur de retour comme argument. Si le contrôle atteint la fin de main sans rencontrer de déclaration de retour, l'effet est celui de l'exécution

return 0;

Le standard C ++ dit explicitement "Il [la fonction principale] doit avoir un type de retour de type int, mais sinon son type est défini par l'implémentation", et requiert les deux mêmes signatures que le standard C pour être pris en charge en option. Ainsi, un 'void main ()' n'est directement pas autorisé par la norme C ++, bien qu'il ne puisse rien faire pour arrêter une implémentation non standard autorisant des alternatives. Notez que C ++ interdit à l'utilisateur d'appeler main(mais pas la norme C).

Il y a un paragraphe du §18.5 Début et fin dans la norme C ++ 11 qui est identique au paragraphe du §7.22.4.4 La exitfonction dans la norme C11 (citée ci-dessus), à l'exception d'une note de bas de page (qui documente simplement cela EXIT_SUCCESSet qui EXIT_FAILUREest définie dans <cstdlib>).

Norme C - Extension commune

Classiquement, les systèmes Unix prennent en charge une troisième variante:

int main(int argc, char **argv, char **envp) { ... }

Le troisième argument est une liste de pointeurs vers des chaînes terminée par un caractère nul, chacune étant une variable d'environnement qui a un nom, un signe égal et une valeur (éventuellement vide). Si vous ne l'utilisez pas, vous pouvez toujours accéder à l'environnement via ' extern char **environ;'. Cette variable globale est unique parmi celles de POSIX en ce qu'elle n'a pas d'en-tête qui la déclare.

Ceci est reconnu par la norme C comme une extension commune, documentée à l'annexe J:

J.5.1 Arguments d'environnement

¶1 Dans un environnement hébergé, la fonction principale reçoit un troisième argument,, char *envp[]qui pointe vers un tableau de pointeurs à terminaison nulle char, chacun pointant vers une chaîne qui fournit des informations sur l'environnement pour cette exécution du programme (5.1. 2.2.1).

Microsoft C

Le compilateur Microsoft VS 2010 est intéressant. Le site Web dit:

La syntaxe de déclaration de main est

 int main();

ou, éventuellement,

int main(int argc, char *argv[], char *envp[]);

Alternativement, les fonctions mainet wmainpeuvent être déclarées comme retournant void(pas de valeur de retour). Si vous déclarez mainou wmainque vous retournez null, vous ne pouvez pas renvoyer un code de sortie au processus parent ou au système d'exploitation à l'aide d'une instruction return. Pour renvoyer un code de sortie lorsque mainou wmainest déclaré en tant que void, vous devez utiliser la exitfonction.

Il n'est pas clair pour moi ce qui se passe (quel code de sortie est retourné au parent ou au système d'exploitation) lorsqu'un programme se void main()ferme - et le site Web de MS est également silencieux.

Fait intéressant, MS ne prescrit pas la version à deux arguments main()requise par les normes C et C ++. Il ne prescrit qu'une forme à trois arguments où se trouve le troisième argument char **envp, un pointeur vers une liste de variables d'environnement.

La page Microsoft répertorie également quelques autres alternatives - wmain()qui prennent des chaînes de caractères larges, et quelques autres.

La version Microsoft Visual Studio 2005 de cette page ne figure pas void main()comme alternative. Les versions à partir de Microsoft Visual Studio 2008 le font.

Norme C - Environnement autonome

Comme indiqué précédemment, les exigences ci-dessus s'appliquent aux environnements hébergés. Si vous travaillez avec un environnement autonome (qui est l'alternative à un environnement hébergé), la norme a beaucoup moins à dire. Pour un environnement autonome, la fonction appelée au démarrage du programme n'a pas besoin d'être appelée mainet il n'y a aucune contrainte sur son type de retour. La norme dit:

5.1.2 Environnements d'exécution

Deux environnements d'exécution sont définis: autonome et hébergé. Dans les deux cas, le démarrage du programme se produit lorsqu'une fonction C désignée est appelée par l'environnement d'exécution. Tous les objets avec une durée de stockage statique doivent être initialisés (définis sur leurs valeurs initiales) avant le démarrage du programme. La manière et le moment d'une telle initialisation ne sont par ailleurs pas spécifiés. La fin du programme renvoie le contrôle à l'environnement d'exécution.

5.1.2.1 Environnement autonome

Dans un environnement autonome (dans lequel l'exécution du programme C peut avoir lieu sans aucun avantage d'un système d'exploitation), le nom et le type de la fonction appelée au démarrage du programme sont définis par l'implémentation. Toutes les installations de bibliothèque disponibles pour un programme indépendant, autres que l'ensemble minimal requis par l'article 4, sont définies par l'implémentation.

L'effet de l'arrêt du programme dans un environnement autonome est défini par l'implémentation.

Le renvoi à l'article 4 Conformité se réfère à ceci:

¶5 Un programme strictement conforme doit utiliser uniquement les caractéristiques du langage et de la bibliothèque spécifiés dans la présente Norme internationale. 3) Il ne doit pas produire de sortie dépendante d'un comportement non spécifié, non défini ou défini par l'implémentation, et ne doit pas dépasser une limite d'implémentation minimale.

¶6 Les deux formes d'implémentation conforme sont hébergées et autonomes . Une implémentation hébergée conforme doit accepter tout programme strictement conforme. Une mise en œuvre conforme autoportant accepte tout programme conforme strictement dans lequel l'utilisation des fonctionnalités spécifiées dans la clause bibliothèque (article 7) se limite au contenu des en- têtes standards <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>et <stdnoreturn.h>. Une implémentation conforme peut avoir des extensions (y compris des fonctions de bibliothèque supplémentaires), à condition qu'elles ne modifient pas le comportement d'un programme strictement conforme. 4)

¶7 Un programme conforme est celui qui est acceptable pour une implémentation conforme. 5)

3) Un programme strictement conforme peut utiliser des fonctionnalités conditionnelles (voir 6.10.8.3) à condition que l'utilisation soit protégée par une directive de prétraitement d'inclusion conditionnelle appropriée utilisant la macro associée. Par exemple:

#ifdef __STDC_IEC_559__ /* FE_UPWARD defined */
    /* ... */
    fesetround(FE_UPWARD);
    /* ... */
#endif

4) Cela implique qu'une implémentation conforme ne réserve aucun identifiant autre que ceux explicitement réservés dans la présente Norme internationale.

5) Les programmes strictement conformes sont destinés à être portatifs au maximum parmi les implémentations conformes. Les programmes conformes peuvent dépendre de fonctionnalités non portables d'une implémentation conforme.

Il est à noter que le seul en-tête requis d'un environnement autonome qui définit réellement toutes les fonctions est <stdarg.h>(et même celles-ci peuvent être - et sont souvent - simplement des macros).

Standard C ++ - Environnement autonome

Tout comme la norme C reconnaît à la fois l'environnement hébergé et autonome, la norme C ++ aussi. (Citations de l'ISO / CEI 14882: 2011.)

1.4 Conformité de l'implémentation [intro.compliance]

¶7 Deux types d'implémentations sont définis: une implémentation hébergée et une implémentation autonome . Pour une implémentation hébergée, la présente Norme internationale définit l'ensemble des bibliothèques disponibles. Une implémentation autonome est une implémentation dans laquelle l'exécution peut avoir lieu sans l'avantage d'un système d'exploitation, et possède un ensemble de bibliothèques défini par l'implémentation qui inclut certaines bibliothèques prenant en charge les langues (17.6.1.3).

¶8 Une implémentation conforme peut avoir des extensions (y compris des fonctions de bibliothèque supplémentaires), à condition qu'elles ne modifient pas le comportement d'un programme bien formé. Des implémentations sont nécessaires pour diagnostiquer les programmes qui utilisent de telles extensions mal formées conformément à la présente Norme internationale. Cela fait, cependant, ils peuvent compiler et exécuter de tels programmes.

¶9 Chaque implémentation doit comprendre une documentation qui identifie toutes les constructions à prise en charge conditionnelle qu'elle ne prend pas en charge et définit toutes les caractéristiques spécifiques aux paramètres régionaux. 3

3) Cette documentation définit également le comportement défini par l'implémentation; voir 1.9.

17.6.1.3 Implémentations autonomes [conformité]

Deux types d'implémentations sont définis: hébergé et autonome (1.4). Pour une implémentation hébergée, la présente Norme internationale décrit l'ensemble des en-têtes disponibles.

Une implémentation autonome possède un ensemble d'en-têtes défini par l'implémentation. Cet ensemble doit comprendre au moins les en-têtes indiqués dans le tableau 16.

La version fournie de l' en- tête <cstdlib>doit déclarer au moins les fonctions abort, atexit, at_quick_exit, exitet quick_exit(18,5). Les autres en-têtes répertoriés dans ce tableau doivent répondre aux mêmes exigences que pour une implémentation hébergée.

Tableau 16 - En-têtes C ++ pour les implémentations autonomes

Subclause                           Header(s)
                                    <ciso646>
18.2  Types                         <cstddef>
18.3  Implementation properties     <cfloat> <limits> <climits>
18.4  Integer types                 <cstdint>
18.5  Start and termination         <cstdlib>
18.6  Dynamic memory management     <new>
18.7  Type identification           <typeinfo>
18.8  Exception handling            <exception>
18.9  Initializer lists             <initializer_list>
18.10 Other runtime support         <cstdalign> <cstdarg> <cstdbool>
20.9  Type traits                   <type_traits>
29    Atomics                       <atomic>

Qu'en est-il de l'utilisation int main()en C?

La norme §5.1.2.2.1 de la norme C11 montre la notation préférée -  int main(void)- mais il y a aussi deux exemples dans la norme qui montrent int main(): §6.5.3.4 ¶8 et §6.7.6.3 ¶20 . Maintenant, il est important de noter que les exemples ne sont pas «normatifs»; ils ne sont qu'illustratifs. S'il y a des bogues dans les exemples, ils n'affectent pas directement le texte principal de la norme. Cela dit, ils sont fortement indicatifs du comportement attendu, donc si la norme inclut int main()dans un exemple, cela suggère que ce int main()n'est pas interdit, même si ce n'est pas la notation préférée.

6.5.3.4 Les opérateurs sizeofet_Alignof

¶8 EXEMPLE 3 Dans cet exemple, la taille d'un tableau de longueur variable est calculée et renvoyée par une fonction:

#include <stddef.h>

size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}
int main()
{
    size_t size;
    size = fsize3(10); // fsize3 returns 13
    return 0;
}
Jonathan Leffler
la source
@DavidBowling: Une définition de fonction telle int main(){ … }que spécifie que la fonction ne prend aucun argument, mais ne fournit pas de prototype de fonction, AFAICT. Car main()c'est rarement un problème; cela signifie que si vous avez des appels récursifs à main(), les arguments ne seront pas vérifiés. Pour les autres fonctions, c'est plus un problème - vous avez vraiment besoin d'un prototype dans la portée lorsque la fonction est appelée pour vous assurer que les arguments sont corrects.
Jonathan Leffler
1
@DavidBowling: Normalement, vous n'appelez pas main()récursivement, en dehors d'endroits comme IOCCC. J'ai un programme de test qui le fait - principalement pour la nouveauté. Si vous avez int i = 0; int main() { if (i++ < 10) main(i, i * i); return 0; }et compilez avec GCC et n'incluez pas -Wstrict-prototypes, il compile proprement sous des avertissements stricts. Si c'est le cas main(void), il ne parvient pas à compiler.
Jonathan Leffler
61

Je crois que cela main()devrait revenir soit EXIT_SUCCESSou EXIT_FAILURE. Ils sont définis dansstdlib.h

dmityugov
la source
20
0 est également standard.
Chris Young
2
@ChrisYoung Il y a EXIT_SUCCESSet EXIT_FAILUREparce que certains systèmes d'exploitation historiques (VMS?) Ont utilisé un nombre différent de 0 pour indiquer le succès. C'est 0 partout de nos jours.
fuz
5
@FUZxxl vous avez raison, mais ce n'est pas en conflit avec mon commentaire. EXIT_SUCCESS peut en effet être différent de zéro, mais les normes (C89, C99, C11) définissent toutes 0 (ainsi que EXIT_SUCCESS) pour être également une forme définie par l'implémentation de la terminaison réussie du statut.
Chris Young
2
@FUZxxl: Il est vrai que le VMS a utilisé des valeurs impaires (comme 1) pour indiquer le succès et des valeurs paires (comme 0) pour indiquer l'échec. Malheureusement, la norme ANSI C d'origine a été interprétée comme signifiant que EXIT_SUCCESS devait être égal à 0, donc le retour de EXIT_SUCCESS de main a eu exactement le mauvais comportement sur VMS. La chose portable à faire pour VMS était d'utiliser exit(EXIT_SUCCESS), ce qui faisait toujours la bonne chose.
Adrian McCarthy
1
5.1.2.2.3 "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 exit avec la valeur renvoyée par la fonction principale comme argument; 11) atteindre le} qui termine la fonction principale renvoie une valeur de 0. "
Lundin
38

Notez que les normes C et C ++ définissent deux types d'implémentations: autonomes et hébergées.

  • Environnement hébergé C90

    Formulaires autorisés 1 :

    int main (void)
    int main (int argc, char *argv[])
    
    main (void)
    main (int argc, char *argv[])
    /*... etc, similar forms with implicit int */

    Commentaires:

    Les deux premiers sont explicitement indiqués comme les formes autorisées, les autres sont implicitement autorisés car C90 a autorisé "implicit int" pour le type de retour et les paramètres de fonction. Aucun autre formulaire n'est autorisé.

  • Environnement autoportant C90

    Toute forme ou nom de principal est autorisé 2 .

  • Environnement hébergé C99

    Formulaires autorisés 3 :

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */

    Commentaires:

    C99 a supprimé "implicit int" et main()n'est donc plus valide.

    Une phrase étrange et ambiguë "ou d'une autre manière définie par la mise en œuvre" a été introduite. Cela peut être interprété comme «les paramètres int main()peuvent varier» ou comme «principal peut avoir n'importe quelle forme définie par l'implémentation».

    Certains compilateurs ont choisi d'interpréter la norme de cette dernière manière. On peut sans doute affirmer qu'ils ne sont pas strictement conformes en citant la norme en elle-même, car elle est ambiguë.

    Cependant, autoriser des formes complètement sauvages main()n'était probablement pas (?) L'intention de cette nouvelle phrase. La justification C99 (non normative) implique que la phrase se réfère à des paramètres supplémentaires à int main 4 .

    Pourtant, la section relative à l'arrêt du programme d'environnement hébergé continue de discuter du cas où main ne retourne pas int 5 . Bien que cette section ne soit pas normative sur la façon dont main doit être déclarée, elle implique certainement que main pourrait être déclarée de manière complètement définie par l'implémentation, même sur les systèmes hébergés.

  • Environnement autonome C99

    Toute forme ou nom de principal est autorisé 6 .

  • Environnement hébergé C11

    Formulaires autorisés 7 :

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */
  • Environnement autonome C11

    Toute forme ou nom de principal est autorisé 8 .


Notez que int main()n'a jamais été répertorié comme un formulaire valide pour toute implémentation hébergée de C dans l'une des versions ci-dessus. En C, contrairement à C ++, ()et (void)ont des significations différentes. Le premier est une fonction obsolète qui peut être supprimée de la langue. Voir les futures orientations linguistiques du C11:

6.11.6 Déclarateurs de fonctions

L'utilisation de déclarateurs de fonctions avec des parenthèses vides (et non des déclarants de type paramètre de type prototype) est une fonction obsolète.


  • Environnement hébergé C ++ 03

    Formulaires autorisés 9 :

    int main ()
    int main (int argc, char *argv[])

    Commentaires:

    Notez la parenthèse vide dans le premier formulaire. C ++ et C sont différents dans ce cas, car en C ++, cela signifie que la fonction ne prend aucun paramètre. Mais en C, cela signifie qu'il peut prendre n'importe quel paramètre.

  • Environnement autonome C ++ 03

    Le nom de la fonction appelée au démarrage est défini par l'implémentation. S'il est nommé, main()il doit suivre les formulaires indiqués 10 :

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])
  • Environnement hébergé C ++ 11

    Formulaires autorisés 11 :

    int main ()
    int main (int argc, char *argv[])

    Commentaires:

    Le texte de la norme a été modifié, mais il a la même signification.

  • Environnement autonome C ++ 11

    Le nom de la fonction appelée au démarrage est défini par l'implémentation. S'il est nommé, main()il doit suivre les formulaires indiqués 12 :

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])

Références

  1. ANSI X3.159-1989 2.1.2.2 Environnement hébergé. "Démarrage du programme"

    La fonction appelée au démarrage du programme est nommée main. L'implémentation ne déclare aucun prototype pour cette fonction. Il doit être défini avec un type de retour de int et sans paramètres:

    int main(void) { /* ... */ } 

    ou avec deux paramètres (appelés ici argc et argv, bien que tous les noms puissent être utilisés, car ils sont locaux à la fonction dans laquelle ils sont déclarés):

    int main(int argc, char *argv[]) { /* ... */ }
  2. ANSI X3.159-1989 2.1.2.1 Environnement autonome:

    Dans un environnement autonome (dans lequel l'exécution du programme C peut avoir lieu sans aucun avantage d'un système d'exploitation), le nom et le type de la fonction appelée au démarrage du programme sont définis par l'implémentation.

  3. ISO 9899: 1999 5.1.2.2 Environnement hébergé -> 5.1.2.2.1 Démarrage du programme

    La fonction appelée au démarrage du programme est nommée main. L'implémentation ne déclare aucun prototype pour cette fonction. Il doit être défini avec un type de retour de int et sans paramètres:

    int main(void) { /* ... */ } 

    ou avec deux paramètres (appelés ici argc et argv, bien que tous les noms puissent être utilisés, car ils sont locaux à la fonction dans laquelle ils sont déclarés):

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

    ou équivalent; 9) ou d'une autre manière définie par la mise en œuvre.

  4. Justification de la Norme internationale - Langages de programmation - C, révision 5.10. 5.1.2.2 Environnement hébergé -> 5.1.2.2.1 Démarrage du programme

    Le comportement des arguments à main et de l'interaction de sortie, main et atexit (voir §7.20.4.2) a été codifié pour limiter une variété indésirable dans la représentation des chaînes argv et dans le sens des valeurs renvoyées par main.

    La spécification d'argc et d'argv comme arguments de main reconnaît une pratique antérieure étendue. argv [argc] doit être un pointeur nul pour fournir un contrôle redondant pour la fin de la liste, également sur la base d'une pratique courante.

    main est la seule fonction qui peut être déclarée de manière portable avec zéro ou deux arguments. (Le nombre d'arguments d'autres fonctions doit correspondre exactement entre l'appel et la définition.) Ce cas spécial reconnaît simplement la pratique répandue de laisser les arguments à main lorsque le programme n'accède pas aux chaînes d'arguments du programme. Bien que de nombreuses implémentations prennent en charge plus de deux arguments pour main, une telle pratique n'est ni bénie ni interdite par la norme; un programme qui définit main avec trois arguments n'est pas strictement conforme (voir §J.5.1.).

  5. ISO 9899: 1999 5.1.2.2 Environnement hébergé -> 5.1.2.2.3 Arrêt du programme

    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 exit avec la valeur renvoyée par la fonction principale comme argument; 11) atteindre le }qui se termine la fonction principale renvoie une valeur de 0. Si le type de retour n'est pas compatible avec int, l'état de terminaison renvoyé à l'environnement hôte n'est pas spécifié.

  6. ISO 9899: 1999 5.1.2.1 Environnement autonome

    Dans un environnement autonome (dans lequel l'exécution du programme C peut avoir lieu sans aucun avantage d'un système d'exploitation), le nom et le type de la fonction appelée au démarrage du programme sont définis par l'implémentation.

  7. ISO 9899: 2011 5.1.2.2 Environnement hébergé -> 5.1.2.2.1 Démarrage du programme

    Cette section est identique à la C99 citée ci-dessus.

  8. ISO 9899: 1999 5.1.2.1 Environnement autonome

    Cette section est identique à la C99 citée ci-dessus.

  9. ISO 14882: 2003 3.6.1 Fonction principale

    Une implémentation ne doit pas prédéfinir la fonction principale. Cette fonction ne doit pas être surchargée. Il doit avoir un type de retour de type int, mais sinon son type est défini par l'implémentation. Toutes les implémentations doivent permettre les deux définitions suivantes de main:

    int main() { /* ... */ }

    et

    int main(int argc, char* argv[]) { /* ... */ }
  10. ISO 14882: 2003 3.6.1 Fonction principale

    Il est défini par l'implémentation si un programme dans un environnement autonome est nécessaire pour définir une fonction principale.

  11. ISO 14882: 2011 3.6.1 Fonction principale

    Une implémentation ne doit pas prédéfinir la fonction principale. Cette fonction ne doit pas être surchargée. Il doit avoir un type de retour de type int, mais sinon son type est défini par l'implémentation. Toutes les implémentations doivent permettre à la fois

    - une fonction de () retournant int et

    - une fonction de (int, pointeur vers pointeur vers char) renvoyant int

    comme type de principal (8.3.5).

  12. ISO 14882: 2011 3.6.1 Fonction principale

    Cette section est identique à celle de C ++ 03 citée ci-dessus.

Lundin
la source
Une question: les normes C ++ signifient-elles que la signature de la fonction de démarrage dans les environnements autonomes est également définie par l'implémentation? Par exemple, une implémentation aurait pu définir la fonction de démarrage comme: int my_startup_function ()ou int my_startup_function (int argc, char *argv[])mais peut-elle avoir, par exemple: char my_startup_function (long argc, int *argv[])comme fonction de démarrage également? Je suppose que non, non? De plus, n'est-ce pas aussi ambigu?
Utku
@Utku Il peut avoir n'importe quelle signature, tant qu'il n'est pas nommé main()car il doit alors utiliser l'une des signatures répertoriées. J'imagine que la plus écrasante serait la plus courante void my_startup_function (), car cela n'a pas de sens de revenir du programme sur les systèmes autonomes.
Lundin
1
Je vois. Mais s'il est autorisé à utiliser n'importe quel nom et n'importe quelle signature pour la fonction de démarrage, pourquoi ne pas autoriser à utiliser également une signature différente main? Désolé si ce n'est pas une question intelligente, mais je ne pouvais pas comprendre le raisonnement derrière.
Utku
@Utku C et C ++ sont différents là-bas. Quant à savoir pourquoi C ++ applique cela, je n'en ai aucune idée, il n'y a aucune justification. Je soupçonne que le principal coupable (jeu de mots voulu) est Stroustrup qui a très tôt déclaré que le principal devait revenir dans la période. Parce que quand il a fait la première version C ++, il n'était habitué qu'aux systèmes hébergés. Dans le message lié, Stroustrup semble toujours inconscient de l'existence d'implémentations autonomes: par exemple, il fait référence par ignorance au sous-chapitre de l'implémentation hébergée de la norme C, ignorant l'existence du chapitre 5.1.2.1.
Lundin
1
Une chose notable à propos du projet standard C11 est que même s'il func()est considéré comme obsolète, le projet lui-même utilise int main()dans ses propres exemples.
Antti Haapala
29

Retourne 0 en cas de succès et non nul pour l'erreur. Il s'agit de la norme utilisée par les scripts UNIX et DOS pour savoir ce qui s'est passé avec votre programme.

Lou Franco
la source
8

main() dans C89 et K&R C, les types de retour non spécifiés sont définis par défaut sur «int».

return 1? return 0?
  1. Si vous n'écrivez pas de déclaration de retour dans int main(), la fermeture {renverra 0 par défaut.

  2. return 0ou return 1sera reçu par le processus parent. Dans un shell, il va dans une variable shell, et si vous exécutez votre programme sous forme de shell et n'utilisez pas cette variable, vous n'avez pas à vous soucier de la valeur de retour de main().

Voir Comment puis-je obtenir ce que ma fonction principale a renvoyé? .

$ ./a.out
$ echo $?

De cette façon, vous pouvez voir que c'est la variable $?qui reçoit l'octet le moins significatif de la valeur de retour de main().

Dans les scripts Unix et DOS, return 0en cas de succès et non nul pour l'erreur sont généralement retournés. Il s'agit de la norme utilisée par les scripts Unix et DOS pour découvrir ce qui s'est passé avec votre programme et contrôler l'ensemble du flux.

Jeegar Patel
la source
4
À proprement parler, $?n'est pas une variable d'environnement; il s'agit d'une variable prédéfinie (ou intégrée) du shell. La différence est difficile à repérer, mais si vous exécutez env(sans aucun argument), elle imprime l'environnement et $?ne sera pas affichée dans l'environnement.
Jonathan Leffler
1
Le retour automatique de 0 lorsque les "chutes de fin" principales se fait uniquement en C ++ et C99 et non en C90.
Kaz
Typo: "fermeture {" devrait être }. SO ne me permettra pas de faire un montage aussi petit.
Spencer
7

Gardez à l'esprit que, même si vous retournez un entier, certains systèmes d'exploitation (Windows) tronquent la valeur renvoyée en un seul octet (0-255).

Ferruccio
la source
4
Unix fait de même, comme le font probablement la plupart des autres systèmes d'exploitation. Je sais que VMS fait des choses tellement incroyables avec ça que retourner autre chose que EXIT_SUCCESS ou EXIT_FAILURE demande des ennuis.
Leon Timmermans
2
MSDN demande à différer: lorsqu'il est signalé via mscorlib, un code de sortie est un entier 32 bits signé . Cela semble impliquer que les bibliothèques d'exécution C qui tronquent les codes de sortie sont défectueuses.
Oui, c'est incorrect. Sous Windows, un entier 32 bits est renvoyé (et converti en unsigned). C'est la même chose sur les systèmes UNIX avec des entiers 32 bits. Mais les shells de style UNIX sur l'un ou l'autre système ne conservent généralement qu'un entier 8 bits non signé.
John McFarlane
4

La valeur de retour peut être utilisée par le système d'exploitation pour vérifier la fermeture du programme.

La valeur de retour 0 signifie généralement OK dans la plupart des systèmes d'exploitation (ceux auxquels je pense de toute façon).

Il peut également être vérifié lorsque vous appelez un processus vous-même et voyez si le programme s'est terminé et s'est terminé correctement.

Ce n'est PAS seulement une convention de programmation.

Yochai Timmer
la source
Rien dans la question n'indique la présence d'un système opératoire. Renvoyer une valeur n'a aucun sens dans un système autonome.
Lundin
3

La valeur de retour de main()montre comment le programme s'est arrêté. Si la valeur de retour est, zerocela signifie que l'exécution a réussi, tandis que toute valeur non nulle représentera que quelque chose s'est mal passé dans l'exécution.

fuddin
la source
1
Ceci est un commentaire et non une réponse à la question.
Lundin
2

J'avais l'impression que la norme spécifie que le principal n'a pas besoin d'une valeur de retour car un retour réussi était basé sur le système d'exploitation (zéro dans l'un pourrait être un succès ou un échec dans un autre), donc l'absence de retour était un signal pour le compilateur pour insérer le retour réussi lui-même.

Cependant, je retourne généralement 0.

graham.reeds
la source
C99 (et C ++ 98) vous permettent d'omettre l'instruction return de main; C89 ne vous permet pas d'omettre l'instruction de retour.
Jonathan Leffler
Ceci est un commentaire et non une réponse.
Lundin
Cela ne fournit pas de réponse à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous son article.
Steve Lillis
6
@SteveLillis: En 2008, SO n'avait pas de section de commentaires.
graham.reeds
2

Renvoyer 0 devrait indiquer au programmeur que le programme a correctement terminé le travail.

Vamsi Pavan Mahesh
la source
Le retour de 1 main()signale normalement qu'une erreur s'est produite; renvoyer 0 signale le succès. Si vos programmes échouent toujours, alors 1 est OK, mais ce n'est pas la meilleure idée.
Jonathan Leffler
1
@JonathanLeffler: Le sens de retour 1de mainest défini par l' implémentation. Les seules valeurs définies par le langage sont 0, EXIT_SUCCESS(souvent définies comme 0), et EXIT_FAILURE. Dans OpenVMS, return 1;indique une terminaison réussie .
Keith Thompson
Le VMS n'est pas «normal» - au sens de ce que j'ai dit. N'est-ce pas quelque chose comme «toute valeur étrange est le succès; même les valeurs sont l'échec »sur VMS?
Jonathan Leffler
2

Omettre return 0

Lorsqu'un programme C ou C ++ atteint la fin du maincompilateur génère automatiquement du code pour retourner 0, il n'est donc pas nécessaire de mettre return 0;explicitement à la fin de main.

Remarque: lorsque je fais cette suggestion, elle est presque invariablement suivie d'un des deux types de commentaires: "Je ne le savais pas." ou "C'est un mauvais conseil!" Ma justification est qu'il est sûr et utile de s'appuyer sur le comportement du compilateur explicitement pris en charge par la norme. Pour C, depuis C99; voir ISO / IEC 9899: 1999 section 5.1.2.2.3:

[...] un retour de l'appel initial à la mainfonction équivaut à appeler la exitfonction avec la valeur renvoyée par la mainfonction comme argument; atteindre la }fin de la mainfonction renvoie une valeur de 0.

Pour C ++, depuis la première norme en 1998; voir ISO / IEC 14882: 1998 section 3.6.1:

Si le contrôle atteint la fin de main principale sans rencontrer de déclaration de retour, l'effet est celui de l'exécution du retour 0;

Depuis lors, toutes les versions des deux normes (C99 et C ++ 98) ont conservé la même idée. Nous nous appuyons sur les fonctions membres générées automatiquement en C ++, et peu de gens écrivent des return;instructions explicites à la fin d'une voidfonction. Les raisons de ne pas le faire semblent se résumer à "ça a l'air bizarre" . Si, comme moi, vous êtes curieux de connaître la justification du changement de la norme C, lisez cette question . Notez également qu'au début des années 90, cela était considéré comme une "pratique bâclée" car il s'agissait à l'époque d'un comportement indéfini (bien que largement soutenu).

En outre, les directives de base C ++ contiennent plusieurs instances d'omission return 0;à la fin mainet aucune instance dans laquelle un retour explicite est écrit. Bien qu'il n'y ait pas encore de directive spécifique sur ce sujet particulier dans ce document, cela semble au moins une approbation tacite de la pratique.

Je préconise donc de l'omettre; d'autres ne sont pas d'accord (souvent avec véhémence!) Dans tous les cas, si vous rencontrez du code qui l'omet, vous saurez qu'il est explicitement pris en charge par la norme et vous saurez ce que cela signifie.

Edward
la source
2
C'est un mauvais conseil car les compilateurs qui n'implémentent que C89, et non une norme ultérieure, sont toujours extrêmement courants (j'écris ceci en 2017) et le resteront dans un avenir prévisible. Par exemple, la dernière fois que j'ai vérifié qu'aucune version des compilateurs de Microsoft n'avait implémenté C99, et je crois comprendre que cela est également typique des compilateurs de systèmes intégrés qui ne sont pas GCC.
zwol
4
@zwol: Quiconque n'a d'autre choix que d'utiliser un compilateur obsolète de 28 ans a probablement plus de problèmes que de décider d'inclure explicitement return 0;, mais je noterais que de nombreux compilateurs de cette époque ont également implémenté un implicite return 0;avant même qu'il ne soit normalisé.
Edward
2
En fait, je fais beaucoup de travail sur les systèmes embarqués et je n'ai pas rencontré de compilateur qui ne prend pas en charge implicitement return 0depuis plus d'une décennie. Les versions actuelles de Microsoft C le prennent également en charge . Peut-être que vos informations sont obsolètes?
Edward
2
Je peux apprécier que cela soit controversé en C, presque (per @zwol). En C ++, toute controverse autour de cela est un pur non-sens.
Courses de légèreté en orbite le
2
@Edward Je n'ai pas dit que la controverse n'existait pas, j'ai dit que c'était absurde: P
Courses de légèreté en orbite le
1

Que retourner dépend de ce que vous voulez faire avec l'exécutable. Par exemple, si vous utilisez votre programme avec un shell de ligne de commande, vous devez retourner 0 pour un succès et un non nul pour un échec. Ensuite, vous pourrez utiliser le programme dans des shells avec un traitement conditionnel en fonction du résultat de votre code. Vous pouvez également attribuer une valeur différente de zéro selon votre interprétation, par exemple pour les erreurs critiques, différents points de sortie de programme pourraient terminer un programme avec différentes valeurs de sortie, et qui est disponible pour le shell appelant qui peut décider quoi faire en inspectant la valeur retournée. Si le code n'est pas destiné à être utilisé avec des shells et que la valeur renvoyée ne dérange personne, il peut être omis. J'utilise personnellement la signatureint main (void) { .. return 0; .. }

phoxis
la source
Le format de main () est déterminé par l'implémentation, c'est-à-dire le compilateur. Le programmeur ne choisit pas le formulaire à choisir, sauf lorsqu'un compilateur prend en charge plusieurs formulaires.
Lundin
@Lundin Le type de retour sera implémenté par l'implémentation. Mais la valeur à renvoyer est décidée par le programmeur. C99 La section 5.1.2.2.3 mentionne que le type de retour de mainest compatible avec int. Le retour intne sera donc pas un problème. Bien que d'autres types de retour soient autorisés, mais dans ce cas, la variable d'environnement ayant la valeur de retour ne sera pas spécifiée. Mais si un programmeur le fait return 0;dans bash, il peut être utilisé pour créer des branches.
phoxis
1

Si vous avez vraiment des problèmes liés à l'efficacité du retour d'un entier à partir d'un processus, vous devriez probablement éviter d'appeler ce processus tant de fois que cette valeur de retour devient un problème.

Si vous faites cela (appelez un processus tant de fois), vous devriez trouver un moyen de mettre votre logique directement dans l'appelant, ou dans un fichier DLL, sans allouer un processus spécifique pour chaque appel; les allocations de processus multiples vous posent le problème d'efficacité pertinent dans ce cas.

En détail, si vous voulez seulement savoir si le retour de 0 est plus ou moins efficace que le retour de 1, cela peut dépendre du compilateur dans certains cas, mais de manière générique, en supposant qu'ils sont lus à partir de la même source (local, champ, constant, intégré dans le code, le résultat de la fonction, etc.), il nécessite exactement le même nombre de cycles d'horloge.

Luca C.
la source
1

Voici une petite démonstration de l'utilisation des codes retour ...

Lorsque vous utilisez les divers outils fournis par le terminal Linux, vous pouvez utiliser le code retour, par exemple pour la gestion des erreurs une fois le processus terminé. Imaginez que le fichier texte suivant myfile soit présent:

Ceci est un exemple afin de vérifier le fonctionnement de grep.

Lorsque vous exécutez la commande grep, un processus est créé. Une fois qu'il a traversé (et n'a pas cassé), il retourne du code entre 0 et 255. Par exemple:

$ grep order myfile

Si tu fais

$ echo $?
$ 0

vous obtiendrez un 0. Pourquoi? Parce que grep a trouvé une correspondance et a renvoyé un code de sortie 0, qui est la valeur habituelle pour quitter avec succès. Vérifions-le à nouveau mais avec quelque chose qui n'est pas dans notre fichier texte et donc aucune correspondance ne sera trouvée:

$ grep foo myfile
$ echo $?
$ 1

Étant donné que grep n'a pas réussi à faire correspondre le jeton "foo" avec le contenu de notre fichier, le code de retour est 1 (c'est le cas habituel en cas d'échec, mais comme indiqué ci-dessus, vous avez le choix entre de nombreuses valeurs).

Maintenant, le script bash suivant (tapez-le simplement dans un terminal Linux) bien que très basique devrait donner une idée de la gestion des erreurs:

$ grep foo myfile
$ CHECK=$?
$ [ $CHECK -eq 0] && echo 'Match found'
$ [ $CHECK -ne 0] && echo 'No match was found'
$ No match was found

Après la deuxième ligne, rien n'est imprimé sur le terminal car "foo" a fait grep retourner 1 et nous vérifions si le code de retour de grep était égal à 0. La deuxième instruction conditionnelle fait écho à son message dans la dernière ligne car elle est vraie en raison de CHECK == 1.

Comme vous pouvez voir si vous appelez ceci et ce processus, il est parfois essentiel de voir ce qu'il a retourné (par la valeur de retour de main ()).

rbaleksandar
la source
Dans un script shell, vous utiliseriez if grep foo myfile; then echo 'Match found'; else echo 'No match was found'; fi- tester directement le statut de retour. Si vous souhaitez capturer l'état (pour les rapports, etc.), vous utilisez une affectation. Vous pouvez utiliser if grep foo myfile; CHECK=$?; [ "$CHECK" = 0 ]; then echo 'Match found'; else echo 'No match was found'; fiou utiliser trois lignes. Vous pouvez également utiliser les options -set -qpour grepempêcher les correspondances ou les messages d'erreur de routine d'apparaître. Cependant, ce sont les minuties du shell - le point clé, que l'état de sortie peut être utile - est OK.
Jonathan Leffler
1

Quelle est la manière correcte (la plus efficace) de définir la fonction main () en C et C ++ - int main () ou void main () - et pourquoi?

Ces mots «(le plus efficace)» ne changent pas la question. À moins que vous ne soyez dans un environnement autonome, il existe une façon universellement correcte de déclarer main(), et c'est comme retourner int.

Que devrait main()retourner en C et C ++?

Ce n'est pas ce qui devrait main() revenir, c'est ce qui main() revient. main()est, bien sûr, une fonction que quelqu'un d'autre appelle. Vous n'avez aucun contrôle sur le code qui appelle main(). Par conséquent, vous devez déclarer main()avec une signature de type correct pour correspondre à son appelant. Vous n'avez tout simplement pas le choix en la matière. Vous n'avez pas à vous demander ce qui est plus ou moins efficace, ou ce qui est meilleur ou pire style, ou quelque chose comme ça, car la réponse est déjà parfaitement bien définie, pour vous, par les normes C et C +. Suivez-les.

Si int main () alors retourne 1 ou retourne 0?

0 pour le succès, différent de zéro pour l'échec. Encore une fois, ce n'est pas quelque chose que vous devez (ou obtenir) choisir: il est défini par l'interface à laquelle vous êtes censé vous conformer.

Sommet Steve
la source