Quelle est la bonne déclaration de main?

147

Quelle est la signature correcte de la mainfonction en C ++? Quel est le type de retour correct et que signifie renvoyer une valeur main? Quels sont les types de paramètres autorisés et quelle est leur signification?

Ce système est-il spécifique? Ces règles ont-elles changé au fil du temps? Que se passe-t-il si je les enfreins?

fredoverflow
la source
1
Ceci est très étroitement lié à, ou en double, ce qui devrait mainretourner en C et C ++ .
Jonathan Leffler
@JonathanLeffler Sans blague ... il a été ajouté à la liste des doublons dans la révision 6 il y a environ 8 mois.
fredoverflow

Réponses:

192

La mainfonction doit être déclarée en tant que fonction non membre dans l'espace de noms global. Cela signifie qu'il ne peut pas être une fonction membre statique ou non statique d'une classe, ni ne peut être placé dans un espace de noms (même l'espace de noms sans nom).

Le nom mainn'est pas réservé en C ++ sauf en tant que fonction dans l'espace de noms global. Vous êtes libre de déclarer d'autres entités nommées main, y compris entre autres, des classes, des variables, des énumérations, des fonctions membres et des fonctions non membres qui ne sont pas dans l'espace de noms global.

Vous pouvez déclarer une fonction nommée en maintant que fonction membre ou dans un espace de noms, mais une telle fonction ne serait pas la mainfonction qui désigne le début du programme.

La mainfonction ne peut pas être déclarée comme staticou inline. Il ne peut pas non plus être surchargé; il ne peut y avoir qu'une seule fonction nommée maindans l'espace de noms global.

La mainfonction ne peut pas être utilisée dans votre programme: vous n'êtes pas autorisé à appeler la mainfonction de n'importe où dans votre code, ni à prendre son adresse.

Le type de retour de maindoit êtreint . Aucun autre type de retour n'est autorisé (cette règle est en gras car il est très courant de voir des programmes incorrects qui se déclarent mainavec un type de retour de void; c'est probablement la règle la plus fréquemment violée concernant la mainfonction).

Deux déclarations maindoivent être autorisées:

int main()               // (1)
int main(int, char*[])   // (2)

Dans (1) , il n'y a pas de paramètres.

Dans (2) , il y a deux paramètres et ils sont respectivement nommés argcet argv. argvest un pointeur vers un tableau de chaînes C représentant les arguments du programme. argcest le nombre d'arguments dans le argvtableau.

Habituellement, argv[0]contient le nom du programme, mais ce n'est pas toujours le cas. argv[argc]est garanti comme étant un pointeur nul.

Notez que comme un argument de type tableau (comme char*[]) n'est en réalité qu'un argument de type pointeur déguisé, les deux suivants sont tous deux des moyens valides d'écrire (2) et ils signifient tous deux exactement la même chose:

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

Certaines implémentations peuvent autoriser d'autres types et nombres de paramètres; vous devrez vérifier la documentation de votre implémentation pour voir ce qu'elle prend en charge.

main()est censé renvoyer zéro pour indiquer le succès et différent de zéro pour indiquer un échec. Vous n'êtes pas obligé d'écrire explicitement une returninstruction dans main(): si vous laissez main()return sans returninstruction explicite , c'est la même chose que si vous aviez écrit return 0;. Les deux main()fonctions suivantes ont le même comportement:

int main() { }
int main() { return 0; }

Il existe deux macros, EXIT_SUCCESSet EXIT_FAILURE, définies dans <cstdlib>qui peuvent également être renvoyées main()pour indiquer respectivement le succès et l'échec.

La valeur renvoyée par main()est transmise à la exit()fonction, qui met fin au programme.

Notez que tout cela ne s'applique que lors de la compilation pour un environnement hébergé (de manière informelle, un environnement dans lequel vous avez une bibliothèque standard complète et un système d'exploitation exécutant votre programme). Il est également possible de compiler un programme C ++ pour un environnement autonome (par exemple, certains types de systèmes embarqués), auquel cas le démarrage et l'arrêt sont entièrement définis par l'implémentation et une main()fonction peut même ne pas être requise. Si vous écrivez du C ++ pour un système d'exploitation de bureau moderne, vous compilez pour un environnement hébergé.

James McNellis
la source
1
IIRC les seules valeurs de retour garanties sont 0, EXIT_SUCCESS (même effet que 0) et EXIT_FAILURE. EDIT: Ah, OK, d'autres valeurs d'état non nulles peuvent être renvoyées, mais avec une signification définie par l'implémentation. Seul EXIT_FAILURE est garanti d'être interprété d'une manière ou d'une autre comme une valeur d'échec.
Derrick Turk
4
@Synetech: La question se pose dans sa première phrase, "Quelle est la signature correcte de la fonction principale en C ++?" et la question est étiquetée à la fois [c ++] et [c ++ - faq]. Je ne peux pas m'en empêcher si les utilisateurs Java ou C # (ou n'importe qui d'autre) sont toujours confus. C # doit Mainêtre une fonction membre statique car il n'a même pas de fonctions non membres. Même C89 oblige mainà revenir int. Je ne suis pas suffisamment familier avec K&R C pour connaître ses règles exactes, mais j'imagine que cela nécessite également mainde retourner intcar mainsans type de retour était assez courant et sans type = implicite intdans K&R.
James McNellis
3
@Suhail: Parce que le standard du langage dit que le type de retour doit être int.
James McNellis
1
@Suhail: Oui. Votre code ne sera pas correct C ++ et de nombreux compilateurs rejetteront votre code.
James McNellis
2
@Suhail: Visual C ++ autorise un voidtype de retour comme extension de langage . Les compilateurs qui ne le permettent pas incluent GCC et Comeau.
James McNellis
15

À partir de la documentation standard., 3.6.1.2 Fonction principale ,

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 depuis 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] comme pointeurs vers l'initial caractères des chaînes multi-octets terminées par null .....

J'espère que cela pourra aider..

liaK
la source
2
y a-t-il une raison spécifique pour laquelle le type de retour maindevrait être int?
Suhail Gupta
1
@SuhailGupta: Pour que le processus appelant sache si ce processus doit être considéré comme réussi ou non. Permettre de voidcasser ce modèle. Cela n'a même pas vraiment de sens si vous aviez cela signifie «toujours juger le succès». Parce que vous n'aviez aucun moyen de dire si le processus a réellement échoué, avez-vous vraiment réussi? Non, reviens int.
Courses de légèreté en orbite le
4

Le libellé exact de la dernière norme publiée (C ++ 14) est:

Une mise en œuvre doit permettre à la fois

  • une fonction de ()retour intet

  • une fonction de (int, pointeur vers pointeur vers char)retourint

comme type de main.

Cela indique clairement que des orthographes alternatives sont autorisées tant que le type de mainest le type int()ou int(int, char**). Les éléments suivants sont donc également autorisés:

  • int main(void)
  • auto main() -> int
  • int main ( )
  • signed int main()
  • typedef char **a; typedef int b, e; e main(b d, a c)
MM
la source
1
NB. J'ai posté cette réponse comme dans les commentaires d'un autre fil, quelqu'un a essayé de citer ce fil comme preuve qui int main(void)n'était pas correcte en C ++.
MM
3
@Stargateur auto main() -> intn'a pas de type de retour déduit. Faites attention au {in "(auto main () {... is not allowed)" et apprenez à savoir quand vous n'en savez pas encore assez pour ajouter quelque chose de significatif.
3

Les deux réseaux valides sont int main()et int main(int, char*[]). Toute autre chose peut être compilée ou non. Si mainne renvoie pas explicitement une valeur, 0 est retourné implicitement.

métal de pierre
la source
1
Je n'ai jamais vu de code ne pas être compilé lorsque je mentionne le type de retour mainà annuler. Y a-t-il une raison spécifique pour laquelle le type de retour de main doit être int?
Suhail Gupta
4
La spécification du langage indique que main doit avoir un type de retour int. Tout autre type de retour autorisé par votre compilateur est une amélioration spécifique au compilateur. En gros, l'utilisation de void signifie que vous programmez dans un langage similaire mais pas C ++.
stonemetal
2
La raison pour laquelle la norme requiert un intcomme type de retour de mainest que cette valeur est transmise au shell en tant que code de sortie du programme et shattend un int.
uckelman
Peut-être que la raison est la discipline? Il peut y avoir plus d'un chemin. Si le type de retour est, voidils sont tous silencieux. Avec intnous devons définir la valeur de sortie spécifique pour chaque retour de main.
Andreas Spindler
2

Détails sur les valeurs de retour et leur signification

Par 3.6.1 ( [basic.start.main]):

Une instruction return in maina pour effet de quitter la mainfonction (détruisant 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 mainsans rencontrer d' returninstruction, l'effet est celui de l'exécution

return 0;

Le comportement de std::exitest détaillé dans la section 18.5 ( [support.start.term]), et décrit le code d'état:

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

Ben Voigt
la source