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? Si int main()
alors return 1
ou return 0
?
Il existe de nombreux doublons de cette question, notamment:
main()
de C?main()
void main()
et int main()
?main()
en C++main()
? - Pour C++, avec une très bonne réponse en effet.main()
fonctions en Cmain()
en Cint main()
vs void main()
en CApparenté, relié, connexe:
int main(int argc, char **argv)
int main(int argc, char *argv[])
char *envp[]
est le troisième argument de main()
portable?int main()
doit-elle renvoyer une valeur dans tous les compilateurs?main()
en C et C++ est-il laissé à l'utilisateur?int main(){}
compile-t-il?main()
en C++ 14?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é.
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:
int
ne peut pas être omis.main()
. Si vous le faites et que main()
est terminé, il existe un return 0
implicite.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 deint
et sans paramètre:int main(void) { /* ... */ }
ou avec deux paramètres (appelés ici
argc
etargv
, 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 groupeargv[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 parargv[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 deargc
est supérieure à un, les chaînes pointées deargv[1]
àargv[argc-1]
représentent les paramètres du programme.- Les paramètres
argc
etargv
et les chaînes pointées par le tableauargv
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 commeint
, ou le type deargv
peut être écrit sous la formechar **argv
, etc.
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 avecint
, un retour depuis l'appel initial vers la fonctionmain
équivaut à l'appel de la fonctionexit
avec la valeur renvoyée par la fonctionmain
en tant qu'argument;11) atteindre le}
qui termine la fonctionmain
renvoie la valeur 0. Si le type de retour n'est pas compatible avecint
, 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 ouEXIT_SUCCESS
, une forme définie par l'implémentation du statut fin correcte est renvoyée. Si la valeur destatus
estEXIT_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.
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é. Siargc
est différent de zéro, ces arguments doivent être fournis dansargv[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) etargv[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 deargc
ne doit pas être négative. La valeur deargv[argc]
doit être 0. [Remarque: il est recommandé d'ajouter tout paramètre supplémentaire (facultatif) aprèsargv
. —Fin note]¶3 La fonction
main
ne doit pas être utilisée dans un programme. Le lien (3.5) demain
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>
).
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 verschar
, pointant chacun vers une chaîne fournissant des informations sur le environnement pour cette exécution du programme (5.1.2.2.1).
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
etwmain
peuvent également être déclarées comme renvoyantvoid
(aucune valeur renvoyée). Si vous déclarezmain
ouwmain
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 lorsquemain
ouwmain
est déclaré en tant quevoid
, vous devez utiliser la fonctionexit
.
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.
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).
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 fonctionsabort
,atexit
,at_quick_exit
,exit
etquick_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>
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; }
Je crois que main()
devrait renvoyer soit EXIT_SUCCESS
ou EXIT_FAILURE
. Ils sont définis dans stdlib.h
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
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[]) { /* ... */ }
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.
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.
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.).
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é.
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.
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.
ISO 9899: 1999 5.1.2.1 Environnement autoportant
Cette section est identique à celle de la C99 citée ci-dessus.
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[]) { /* ... */ }
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.
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).
ISO 14882: 2011 3.6.1 Fonction principale
Cette section est identique à celle de C++ 03 citée ci-dessus.
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.
main()
dans C89 et K & R C, les types de retour non spécifiés passent par défaut à 'int`.
return 1? return 0?
Si vous n'écrivez pas une instruction return dans int main()
, la fermeture {
renverra 0 par défaut.
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.
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).
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.
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.
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 fonctionexit
avec la valeur renvoyée par la fonctionmain
comme argument; atteindre le}
qui termine la fonctionmain
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.
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.
Renvoyer 0 doit indiquer au programmeur que le programme a terminé le travail avec succès.
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.
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.
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; .. }
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 ()).