web-dev-qa-db-fra.com

Qu'est-ce que main () doit renvoyer en C et C ++?

646
Joel

La valeur de retour pour main devrait indiquer le déroulement du programme. La sortie normale est généralement représentée par une valeur de retour 0 de main. Une sortie anormale est généralement signalée par un retour non nul, mais il n’existe pas de norme pour l’interprétation des codes non-zéro. Comme d'autres l'ont déjà noté, void main() est explicitement interdit par le standard C++ et ne doit pas être utilisé. Les signatures C++ main valides sont les suivantes:

int main()

et

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

ce qui équivaut à

int main(int argc, char** argv)

Il est également intéressant de noter qu'en C++, int main() peut être laissé sans instruction return, auquel cas il renvoie 0 par défaut. Ceci est également vrai pour un programme C99. Que return 0; devrait être omis ou non est sujet à discussion. La gamme de signatures principales valides du programme C est beaucoup plus grande.

De plus, l'efficacité n'est pas un problème avec la fonction main. Il ne peut être entré et quitté qu'une seule fois (en indiquant le début et la fin du programme) conformément à la norme C++. Pour C, le cas est différent et il est permis de rentrer main(), mais cela devrait être évité.

531
workmad3

La réponse acceptée semble être ciblée sur le C++. J'ai donc pensé ajouter une réponse relative au C, qui diffère de plusieurs manières.

ISO/IEC 9899: 1989 (C90):

main() devrait ê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 type de retour int peut être omis car il s'agit d'un paramètre par défaut.

Si une implémentation le permet, main() peut être déclaré d'une autre manière, mais cela rend la mise en oeuvre du programme définie et n'est plus strictement conforme.

La norme définit trois valeurs pour le retour qui sont strictement conformes (c'est-à-dire qui ne dépendent pas du comportement défini par l'implémentation): 0 et EXIT_SUCCESS pour une terminaison réussie et EXIT_FAILURE pour une terminaison infructueuse. . Toutes les autres valeurs sont non standard et définies par l'implémentation. main() doit avoir une instruction explicite return à la fin pour éviter tout comportement indéfini.

Finalement, il n’ya rien de mal du point de vue des normes à appeler main() depuis un programme.

ISO/IEC 9899: 1999 (C99):

Pour C99, tout est comme ci-dessus sauf que:

  • Le type de retour int ne peut pas être omis.
  • Vous pouvez omettre l'instruction return de main(). Si vous le faites et que main() est terminé, il existe un return 0 implicite.
155
Chris Young

Standard C - Environnement hébergé

Pour un environnement hébergé (normal), la norme C11 (ISO/IEC 9899: 2011) indique:

5.1.2.2.1 Démarrage du programme

La fonction appelée au démarrage du programme s'appelle 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ètre:

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;dix) 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 argc est supérieure à zéro, les membres du groupe argv[0] à argv[argc-1] inclus doivent contenir des pointeurs sur des chaînes, auxquelles l'environnement hôte donne des valeurs définies par l'implémentation avant le démarrage du programme. . Le but est de fournir au programme les 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 à la fois en majuscules et en minuscules, la mise en œuvre doit garantir que les chaînes sont reçues en minuscules.
  • Si la valeur de argc est supérieure à zéro, la chaîne pointée par argv[0] représente le nom du programme. argv[0][0] doit être un caractère nul si le nom du programme n'est pas disponible dans l'environnement hôte. Si la valeur de argc est supérieure à un, les chaînes pointées de argv[1] à argv[argc-1] représentent les paramètres du programme.
  • Les paramètres argc et argv et les chaînes pointées par le tableau argv doivent être modifiables par le programme et conserver leurs dernières valeurs stockées entre le démarrage et la terminaison du programme.

dix) Ainsi, int peut être remplacé par un nom de type défini comme int, ou le type de argv peut être écrit sous la forme char **argv, etc.

Fin du programme en C99 ou C11

La valeur renvoyée par main() est transmise à 'l'environnement' de manière définie.

5.1.2.2.3 Fin du programme

1 Si le type de retour de la fonction main est un type compatible avec int, un retour depuis l'appel initial vers la fonction main équivaut à l'appel de la fonction exit avec la valeur renvoyée par la fonction main en tant qu'argument;11) atteindre le } qui termine la fonction main renvoie la valeur 0. Si le type de retour n'est pas compatible avec int, l'état de la terminaison renvoyé à l'environnement hôte n'est pas spécifié.

11) Conformément au 6.2.4, la durée de vie des objets à durée de stockage automatique déclarée dans main aura pris fin dans le premier cas, même si ce n’était pas le cas dans le second.

Notez que 0 est obligatoire en tant que 'succès'. Vous pouvez utiliser EXIT_FAILURE et EXIT_SUCCESS à partir de <stdlib.h> si vous préférez, mais 0 est bien établi et donc 1. Voir aussi Codes de sortie supérieurs à 255 - possible? .

Dans C89 (et donc dans Microsoft C), il n’ya pas d’instruction sur ce qui se passe si la fonction main() est renvoyée mais ne spécifie pas de valeur de retour; cela conduit donc à un comportement indéfini.

7.22.4.4 La fonction exit

¶5 Enfin, le contrôle est renvoyé à l'environnement hôte. Si la valeur de status est égale à zéro ou EXIT_SUCCESS, une forme définie par l'implémentation du statut fin correcte est renvoyée. Si la valeur de status est EXIT_FAILURE, une forme définie par l'implémentation du statut échec de la terminaison 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 mise en œuvre 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 principal:

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

et

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

Dans cette dernière forme, argc doit être le nombre d'arguments transmis au programme à partir de l'environnement dans lequel le programme est exécuté. Si argc est différent de zéro, ces arguments doivent être fournis dans argv[0] à argv[argc-1] en tant que pointeurs vers les caractères initiaux des chaînes multi-octets à terminaison null (NTMBS) (17.5.2.1.4.2) et argv[0] doit ê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 argc ne doit pas être négative. La valeur de argv[argc] doit être 0. [Remarque: il est recommandé d'ajouter tout paramètre supplémentaire (facultatif) après argv. —Fin note]

¶3 La fonction main ne doit pas être utilisée dans un programme. Le lien (3.5) de main est défini par la mise en oeuvre. [...]

¶5 Une instruction return dans main a pour effet de quitter la fonction principale (détruire tout objet à durée de stockage automatique) et d'appeler std::exit avec la valeur de retour comme argument. Si le contrôle atteint la fin de main sans rencontrer d’instruction return, l’effet est le suivant:

return 0;

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

Il existe un paragraphe de §18.5 Début et fin dans la norme C++ 11 identique au paragraphe de §7.22.4.4 La fonction exit dans la norme C11 (citée ci-dessus), à l'exception d'une note de bas de page (qui indique simplement que EXIT_SUCCESS et EXIT_FAILURE sont défini dans <cstdlib>).

Standard C - Extension commune

Classiquement, les systèmes Unix supportent 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 à terminaison nulle, chacune d'entre elles étant une variable d'environnement ayant 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;'. Pendant longtemps, aucun en-tête ne l’avait déclaré, mais la norme POSIX 2008 exige maintenant qu’il soit déclaré dans <unistd.h>.

Ceci est reconnu par le standard C comme une extension commune, documentée dans 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 à zéro, pointant vers char, pointant chacun vers une chaîne fournissant des informations sur le environnement pour cette exécution du programme (5.1.2.2.1).

Microsoft C

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

La syntaxe de déclaration pour main est la suivante:

 int main();

ou, éventuellement,

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

Les fonctions main et wmain peuvent également être déclarées comme renvoyant void (aucune valeur renvoyée). Si vous déclarez main ou wmain comme renvoyant void, vous ne pouvez pas renvoyer de 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 main ou wmain est déclaré en tant que void, vous devez utiliser la fonction exit.

Je ne sais pas ce qui se passe (quel code de sortie est renvoyé au parent ou au système d'exploitation) lorsqu'un programme avec void main() se ferme - et que le site Web MS est également silencieux.

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

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

La version Microsoft Visual Studio 2005 de cette page ne répertorie pas void main() comme alternative. Les versions 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 constitue une 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 main et il n'y a pas de 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 ayant une durée de stockage statique doivent être initialisés (mis à leurs valeurs initiales) avant le démarrage du programme. La manière et le moment de cette initialisation ne sont par ailleurs pas spécifiés. La terminaison 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 autonome, autres que l'ensemble minimal requis par l'article 4, sont définies par la mise en œuvre.

L'effet de la terminaison de programme dans un environnement autonome est défini par la mise en œuvre.

Le renvoi à la clause 4 Conformance fait référence à ceci:

¶5 A programme strictement conforme utilisera uniquement les fonctionnalités de la langue et de la bibliothèque spécifiées dans la présente Norme internationale.3) Il ne doit pas produire de sortie dépendant 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 de mise en œuvre conforme sont hébergée et autonome. Un implémentation hébergée conforme doit accepter tout programme strictement conforme. Un implémentation autoportante conforme acceptera tout programme strictement conforme dans lequel l'utilisation des fonctionnalités spécifiées dans la clause de bibliothèque (clause 7) est limitée au contenu des en-têtes standard <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h> et <stdnoreturn.h>. Une mise en œuvre 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 acceptable pour une implémentation conforme.5)

3) Un programme strictement conforme peut utiliser des fonctions 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 mise en œuvre conforme ne réserve pas d'autres identificateurs que ceux explicitement réservés dans la présente Norme internationale.

5) Les programmes strictement conformes sont destinés à être portables 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 pour un environnement autonome qui définit réellement une fonction est <stdarg.h> (et même celles-ci peuvent être - et sont souvent - de simples macros).

Standard C++ - Environnement autonome

Tout comme la norme C reconnaît les environnements hébergé et autonome, le standard C++ le fait également. (Citations de l'ISO/CEI 14882: 2011.)

1.4 Conformité d'implémentation [intro.compliance]

¶7 Deux types d'implémentations sont définis: a 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 le bénéfice d'un système d'exploitation et qui possède un ensemble de bibliothèques défini par l'implémentation qui inclut certaines bibliothèques de prise en charge de la langue (17.6.1.3).

¶8 Une mise en œuvre 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é. Les implémentations sont nécessaires pour diagnostiquer les programmes qui utilisent de telles extensions mal formées conformément à la présente Norme internationale. Ce faisant, ils peuvent cependant compiler et exécuter de tels programmes.

¶9 Chaque implémentation doit inclure une documentation qui identifie toutes les constructions prises en charge sous condition et non prise 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 [compliance]

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 comporte un ensemble d'en-têtes définis 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, exit et 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 de int main() en C?

La norme §5.1.2.2.1 de la norme C11 indique la notation préférée - int main(void) - mais il existe également deux exemples dans la norme qui indiquent int main(): §6.5.3.4 ¶8 et §6.7.6.3 ¶2 . 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 indiquent fortement le comportement attendu. Ainsi, si le standard inclut int main() dans un exemple, il suggère que 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 sizeof et _Alignof

¶8 EXEMPLE 3 Dans cet exemple, la taille d'un tableau de longueur variable est calculée et renvoyée à partir d'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;
}
110
Jonathan Leffler

Je crois que main() devrait renvoyer soit EXIT_SUCCESS ou EXIT_FAILURE. Ils sont définis dans stdlib.h

59
dmityugov

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

  • environnement hébergé C9

    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 désignés comme les formes autorisées, les autres sont implicitement autorisés car C90 a autorisé "implicit int" pour les paramètres de type et de fonction de retour. Aucune autre forme n'est autorisée.

  • environnement autonome C9

    Toute forme ou nom de main 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 enlevé "implicit int" donc main() n'est 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 de int main() peuvent varier" ou comme "principal peut avoir toute forme définie par la mise en oeuvre".

    Certains compilateurs ont choisi d'interpréter la norme de cette manière. On peut soutenir que l'on ne peut pas facilement 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 de main() n'était probablement pas (?) L'intention de cette nouvelle phrase. La logique C99 (non normative) implique que la phrase se réfère à des paramètres supplémentaires pour int main 4.

    Cependant, la section relative à la terminaison du programme en environnement hébergé continue à se disputer au sujet du cas où main ne 5. Bien que cette section ne soit pas normative sur la manière dont main doit être déclarée, elle implique clairement que main puisse être déclarée de manière complètement définie par la mise en œuvre, même sur des systèmes hébergés.

  • environnement autonome C99

    Toute forme ou nom de main est autorisé 6.

  • environnement hébergé C11

    Formulaires autorisés sept:

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

    Toute forme ou nom de main est autorisé 8.


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

6.11.6 Déclarateurs de fonction

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


  • environnement hébergé C++

    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 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++

    Le nom de la fonction appelée au démarrage est défini par l'implémentation. Si elle s'appelle main(), elle doit suivre les formes indiquées dix:

    // 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 le même sens.

  • environnement autonome C++ 11

    Le nom de la fonction appelée au démarrage est défini par l'implémentation. Si elle s'appelle main(), elle doit suivre les formes indiquées 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 s'appelle 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ètre:

    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 s'appelle 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ètre:

    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 oeuvre.

  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 de main et des interactions entre exit, main et atexit (voir §7.20.4.2) a été codifié afin de limiter certaines différences non désirées dans la représentation des chaînes argv et dans la signification des valeurs renvoyées par main.

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

    main est la seule fonction qui peut être déclarée avec zéro ou deux arguments. (Le nombre d’arguments des autres fonctions doit correspondre exactement entre l’invocation et la définition.) Ce cas spécial reconnaît simplement la pratique répandue consistant à laisser les arguments à la valeur main lorsque le programme n’a pas accès aux chaînes d’arguments du programme. Bien que de nombreuses implémentations prennent en charge plus de deux arguments, cette 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 Fin du programme

    Si le type de retour de la fonction principale est un type compatible avec int, un retour de l'appel initial vers la fonction principale équivaut à appeler la fonction de sortie avec la valeur renvoyée par la fonction principale en tant qu'argument; 11) atteignant le } qui met fin à la fonction principale renvoie la valeur 0. Si le type de retour n'est pas compatible avec int, l'état de la terminaison renvoyé à l'environnement hôte n'est pas spécifié.

  6. ISO 9899: 1999 5.1.2.1 Environnement autoportant

    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 à celle de la C99 citée ci-dessus.

  8. ISO 9899: 1999 5.1.2.1 Environnement autoportant

    Cette section est identique à celle de 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 principal:

    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 requis 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 à pointeur à caractère) renvoyant int

    comme type de main (8.3.5).

  12. ISO 14882: 2011 3.6.1 Fonction principale

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

38
Lundin

Retourne 0 en cas de succès et non nul en cas d'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.

29
Lou Franco

main() dans C89 et K & R C, les types de retour non spécifiés passent par défaut à 'int`.

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

  2. return 0 ou return 1 sera reçu par le processus parent. Dans un shell, il entre dans une variable shell, et si vous exécutez votre programme à partir d'un shell sans utiliser 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 est revenue? .

$ ./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 0 en cas de succès et une valeur autre que zéro en cas d'erreur sont généralement renvoyées. C’est le standard utilisé par les scripts Unix et DOS pour savoir ce qui s’est passé avec votre programme et contrôler l’ensemble du flux.

8
Jeegar Patel

N'oubliez pas que, même si vous renvoyez un int, certains systèmes d'exploitation (Windows) tronquent la valeur renvoyée en un seul octet (0-255).

7
Ferruccio

Le système d'exploitation peut utiliser la valeur de retour pour vérifier le mode de fermeture du programme.

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

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

C'est NOT juste une convention de programmation.

4
Yochai Timmer

La valeur de retour de main() montre comment le programme s'est terminé. Si la valeur de retour est zero, cela signifie que l'exécution a réussi, tandis que toute valeur autre que zéro indique que quelque chose s'est mal passé lors de l'exécution.

3
Fahad Uddin

Omettre return 0

Lorsqu'un programme C ou C++ atteint la fin de main, le compilateur générera automatiquement le code pour renvoyer 0. Il n'est donc pas nécessaire de mettre explicitement return 0; à la fin de main.

Remarque: Lorsque je fais cette suggestion, elle est presque toujours suivie de l'un des deux types de commentaires suivants: "Je ne le savais pas." ou "C'est un mauvais conseil!" Mon raisonnement 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 fonction main équivaut à l'appel de la fonction exit avec la valeur renvoyée par la fonction main comme argument; atteindre le } qui termine la fonction main renvoie une valeur de 0.

Pour C++, depuis le premier standard en 1998; voir ISO/IEC 14882: 1998, section 3.6.1:

Si le contrôle atteint la fin de main sans rencontrer d'instructions return, l'effet est l'exécution de return 0;

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

En outre, Directives de base C++ contient plusieurs instances d'omission de return 0; à la fin de main et 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 sont en désaccord (souvent avec véhémence!) Dans tous les cas, si vous rencontrez un code qui l'omet, vous saurez qu'il est explicitement pris en charge par le standard et vous saurez ce qu'il signifie.

3
Edward

J'avais l'impression que la norme spécifie que main 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 indice pour le compilateur pour insérer le retour réussi lui-même.

Cependant, je retourne généralement 0.

2
graham.reeds

Renvoyer 0 doit indiquer au programmeur que le programme a terminé le travail avec succès.

2
Vamsi Pavan Mahesh

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. Sauf si vous êtes dans un environnement autonome, il existe un moyen universellement correct de déclarer main(), et c'est comme renvoyer int.

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

Ce n'est pas ce que devraitmain() return, mais ce que faitmain() return. main() est bien entendu une fonction appelée par quelqu'un d'autre. 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 à l'appelant. Vous n'avez simplement aucun choix en la matière. Vous n'avez pas à vous demander ce qui est plus ou moins efficace, ni quel style, meilleur ou pire, ou quelque chose du genre, car la réponse est déjà parfaitement bien définie, selon vous, selon les normes C et C +. Suivez-les simplement.

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

0 en cas de succès, non nul en cas d'échec. Encore une fois, ce n’est pas quelque chose que vous devez (ou que vous devez) choisir: c’est défini par l’interface à laquelle vous êtes censé vous conformer.

1
Steve Summit

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

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

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

1
Luca C.

Ce qu'il faut 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 renvoyer 0 pour un succès et un non nul pour un échec. Vous pourrez alors utiliser le programme dans des shells avec un traitement conditionnel en fonction du résultat de votre code. Vous pouvez également affecter toute 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 des valeurs de sortie différentes et disponible pour le shell appelant qui peut décider quoi faire en inspectant la valeur renvoyée. Si le code n'est pas destiné à être utilisé avec des shells et que la valeur renvoyée ne gêne personne, il peut être omis. J'utilise personnellement la signature int main (void) { .. return 0; .. }

1
phoxis

Voici une petite démonstration de l'utilisation des codes de 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:

Voici un exemple pour vérifier le fonctionnement de grep.

Lorsque vous exécutez la commande grep, un processus est créé. Une fois qu'il a traversé (et ne s'est pas cassé), il renvoie un code compris 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 cela à nouveau, mais avec quelque chose qui ne se trouve pas dans notre fichier texte et donc aucune correspondance ne sera trouvée:

$ grep foo myfile
$ echo $?
$ 1

Puisque 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 l'embarras du choix).

Maintenant, le script bash suivant (tapez-le simplement dans un terminal Linux) bien que très basique devrait vous 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 puisque "foo" a fait grep renvoyer 1 et nous vérifions si le code de retour de grep était égal à 0. La deuxième instruction conditionnelle renvoie son message à la dernière ligne car il est vrai 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 renvoyé (à l'aide de la valeur de retour de main ()).

0
rbaleksandar