Quelles sont vraiment les signatures valides pour la fonction principale en C? Je sais:
int main(int argc, char *argv[])
Y en a-t-il d'autres valides?
La norme actuelle au moment de cette réponse (C11) mentionne explicitement ces deux:
int main(void);
int main(int argc, char* argv[]);
bien qu'il mentionne l'expression "ou équivalent" avec la note de bas de page suivante:
Ainsi,
int
peut être remplacé par un nomtypedef
défini commeint
, ou le type deargv
peut être écrit commechar ** argv
, etc.
En outre, il offre également davantage de possibilités (définies par la mise en œuvre).
La section pertinente (section 5.1.2.2.1 de C11, mais cet aspect particulier est inchangé par rapport à C99) indique:
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 deint
et sans paramètres: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; ou d'une autre manière définie par l'implémentation.
S'ils sont déclarés, les paramètres de la fonction
main
doivent obéir aux 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 tableauargv[0]
parargv[argc-1]
inclus doit contenir des pointeurs vers des chaînes, auxquelles l'environnement hôte a donné des valeurs définies par l'implémentation 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
argc
est supérieure à zéro, la chaîne pointée parargv[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 deargc
est supérieure à un, les chaînes pointées parargv[1]
parargv[argc-1]
représente 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 fin du programme.
Notez qu'il s'agit d'un environnement hébergé, ceux que vous voyez normalement dans les programmes C. Un environnement autonome (tel qu'un système embarqué) est beaucoup moins contraint, comme indiqué au 5.1.2.1 de cette même norme:
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.
Pour un environnement hébergé (c'est le normal), la norme C99 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 deint
et sans paramètres: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;9) ou d'une autre manière définie par l'implémentation.
9) Ainsi,
int
peut être remplacé par un nom de typedef défini commeint
, ou le type deargv
peut être écrit commechar **argv
, Etc.
Les normes C11 et C18 disent essentiellement la même chose que la norme C99.
La norme C++ 98 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 main:
int main() { /* ... */ }
et
int main(int argc, char* argv[]) { /* ... */ }
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. Ainsi, un `` void main () '' n'est directement pas autorisé par la norme C++, bien qu'il n'y ait rien qu'il puisse faire pour empêcher une implémentation conforme non standard d'autoriser des alternatives (ni une implémentation conforme standard d'autoriser des alternatives comme extensions de la norme).
Les normes C++ 03, C++ 11, C++ 14 et C++ 17 disent essentiellement la même chose que C++ 98.
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 terminée par null de pointeurs vers des chaînes, dont chacune est 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;
'. Pendant longtemps, il n'y avait pas d'en-tête qui le déclarait, mais la norme POSIX 2008 exige maintenant qu'il soit déclaré dans <unistd.h>
.
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 terminé par null verschar
, chacun pointant vers une chaîne qui fournit des informations sur l'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 de main est
int main();
ou, éventuellement,
int main(int argc, char *argv[], char *envp[]);
Alternativement, les fonctions
main
etwmain
peuvent être déclarées comme retournantvoid
(pas de valeur de retour). Si vous déclarezmain
ouwmain
comme retour nul, 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 lorsquemain
ouwmain
est déclaré commevoid
, vous devez utiliser la fonctionexit
.
Je ne sais pas ce qui se passe (quel code de sortie est retourné au parent ou o/s) lorsqu'un programme avec void main()
se ferme - et 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 vers une liste de variables d'environnement.
La page Microsoft répertorie également quelques autres alternatives - wmain()
qui prend des chaînes de caractères larges, et quelques autres.
La version Microsoft VS 2005 de cette page ne répertorie pas void main()
comme alternative. Les versions à partir de Microsoft VS 2008 le font.
int main()
est-elle identique à int main(void)
?Pour une analyse détaillée, voir la fin de ma réponse à Que doit main()
retourner en C et C++ . (Il semble que j'ai considéré une fois que cette question faisait référence au C++, même si ce n'est pas le cas et ne l'a jamais fait. En C++, il n'y a pas de différence entre int main()
et int main(void)
et int main()
est idiomatique C++.)
En C, il y a une différence entre les deux notations, mais vous ne la remarquez que dans les cas ésotériques. Plus précisément, il y a une différence si vous appelez la fonction main()
à partir de votre propre code, ce que vous êtes autorisé à faire en C et que vous n'êtes pas autorisé à faire en C++.
La notation int main()
ne fournit pas de prototype pour main()
, mais cela n'a d'importance que si vous l'appelez récursivement. Avec int main()
, vous pourriez plus tard (dans la même fonction, ou dans une autre fonction) écrire int rc = main("absolute", "twaddle", 2):
et formellement le compilateur ne devrait pas se plaindre au point de refuser de compiler le code, cependant il pourrait légitimement s'en plaindre (vous en avertir) (et l'utilisation de -Werror
avec GCC convertirait l'avertissement en erreur). Si vous utilisez int main(void)
, l'appel suivant à main()
devrait générer une erreur - vous avez dit que la fonction ne prend aucun argument mais a essayé d'en fournir trois. Bien sûr, vous ne pouvez pas légitimement appeler main()
avant de l'avoir déclaré ou défini (sauf si vous utilisez toujours la sémantique C90) - et l'implémentation ne déclare pas de prototype pour main()
. NB: La norme C11 illustre à la fois int main()
et int main(void)
dans différents exemples - les deux sont valides en C, même s'il y a une différence subtile entre eux.
POSIX prend en charge execve()
, qui à son tour prend en charge
int main(int argc, char *argv[], char *envp[])
L'argument ajouté est l'environnement, c'est-à-dire un tableau de chaînes de la forme NAME = VALUE.
http://en.wikipedia.org/wiki/Main_function_ (programmation) # C_and_C.2B.2B
Outre l'habituelle int main(int argc, char *argv[])
et la POSIX int main(int argc, char **argv, char **envp)
, sur Mac OS X prend également en charge
int main(int argc, char* argv[], char* envp[], char* Apple[]);
Bien sûr, c'est uniquement pour Mac.
Sous Windows, il y a
int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);
comme variante Unicode (en fait, à caractères larges). Bien sûr, il y a WinMain
aussi.
int main(void)
Sous certains OS (par exemple, Windows), ceci est également valide:
int main(int argc, char **argv, char **envp)
où envp
donne un environnement, autrement accessible via getenv()