web-dev-qa-db-fra.com

Quelles sont les signatures valides pour la fonction main () de C?

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?

56
Prady

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 nom typedef défini comme int, ou le type de argv peut être écrit comme char ** 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 de int et sans paramètres:

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

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

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

ou équivalent; 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 tableau argv[0] par argv[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 par argv[0] représente le nom du programme; argv[0][0] doit être le caractère nul si le nom du programme n'est pas disponible dans l'environnement hôte. Si la valeur de argc est supérieure à un, les chaînes pointées par argv[1] par argv[argc-1] représente 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 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.

66
paxdiablo

Standard C

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 de int et sans paramètres:

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

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

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

ou équivalent;9) ou d'une autre manière définie par l'implémentation.

9) Ainsi, int peut être remplacé par un nom de typedef défini comme int, ou le type de argv peut être écrit comme char **argv, Etc.

Les normes C11 et C18 disent essentiellement la même chose que la norme C99.

C++ standard

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.

Extension commune

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

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

Le troisième argument est une liste 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 vers char, chacun pointant vers une chaîne qui fournit des informations sur l'environnement pour cette exécution du programme (5.1.2.2.1).

Microsoft C

Le compilateur Microsoft VS 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 et wmain peuvent être déclarées comme retournant void (pas de valeur de retour). Si vous déclarez main ou wmain 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 lorsque main ou wmain est déclaré comme void, vous devez utiliser la fonction exit.

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.

16
Jonathan Leffler

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.

8
unwind

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.

8
kennytm
int main(void)

Sous certains OS (par exemple, Windows), ceci est également valide:

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

envp donne un environnement, autrement accessible via getenv()

3
flashnik