Certaines des fonctionnalités du langage C qui a commencé comme des hacks qui vient de se passer au travail.
Plusieurs signatures pour les principaux, ainsi que la longueur variable des listes d'arguments, est l'une de ces fonctions.
Les programmeurs remarqué que l'on peut passer des arguments supplémentaires à une fonction, et rien de mauvais ne se passe avec leur compilateur.
C'est le cas si les conventions d'appel sont telles que:
- La fonction d'appel nettoie les arguments.
- Le plus à gauche arguments sont plus près du haut de la pile, ou à la base de la trame de pile, de sorte que fallacieux arguments n'invalident pas l'aborder.
Un ensemble de conventions d'appel qui obéit à ces règles est basée sur la pile passage de paramètres par lequel l'appelant pop les arguments, et ils sont poussés à droite à gauche:
;; pseudo-assembly-language
;; main(argc, argv, envp); call
push envp ;; rightmost argument
push argv ;;
push argc ;; leftmost argument ends up on top of stack
call main
pop ;; caller cleans up
pop
pop
Dans les compilateurs où ce type de convention d'appel est le cas, rien de spécial à faire pour prendre en charge les deux types d' main
, ou même d'autres types. main
peut être une fonction sans arguments, auquel cas il est inconscient des éléments qui ont été poussés sur la pile. Si c'est une fonction de deux arguments, puis il conclut argc
et argv
comme les deux de plus en haut de la pile des éléments. Si c'est une plate-forme spécifique de trois argument variante avec un environnement pointeur (une extension), qui sera trop de travail: il va trouver que le troisième argument est le troisième élément à partir du haut de la pile.
Et donc fixe appel fonctionne pour tous les cas, permettant à un seul, fixes de début de module à être relié à ce programme. Ce module pourrait être écrit en C, une fonction ressemblant à ceci:
/* I'm adding envp to show that even a popular platform-specific variant
can be handled. */
extern int main(int argc, char **argv, char **envp);
void __start(void)
{
/* This is the real startup function for the executable.
It performs a bunch of library initialization. */
/* ... */
/* And then: */
exit(main(argc_from_somewhere, argv_from_somewhere, envp_from_somewhere));
}
En d'autres termes, cette start module appelle juste un trois-argument principal, toujours. Si le principal ne prend pas d'arguments, ou seulement int, char **
, il arrive à bien fonctionner, comme si elle ne prend pas d'arguments, en raison des conventions d'appel.
Si vous décidez de faire ce genre de chose dans votre programme, il serait non-compatibles et considéré comme un comportement non défini par la norme ISO C: déclaration et l'appel d'une fonction dans une manière, et de définir à l'autre. Mais un compilateur de démarrage de truc n'a pas à être portable; il n'est pas guidé par les règles pour la portabilité des programmes.
Mais supposons que les conventions d'appel sont telles qu'il ne peut pas travailler de cette façon. Dans ce cas, le compilateur doit traiter main
spécialement. Quand il constate que c'est la compilation de l' main
la fonction, il peut générer du code qui est compatible avec, par exemple, un trois argument d'appel.
C'est-à-dire, vous écrivez ceci:
int main(void)
{
/* ... */
}
Mais lorsque le compilateur voit, il permet d'effectuer une transformation du code, de sorte que la fonction qu'elle compile ressemble plus à ceci:
int main(int __argc_ignore, char **__argv_ignore, char **__envp_ignore)
{
/* ... */
}
sauf que les noms __argc_ignore
n'est pas littéralement d'exister. Aucun de ces noms ont été ajoutés à votre portée, et il n'y aura pas d'avertissement sur inutilisé arguments.
La transformation du code, le compilateur émettent code avec le bon lien qui sait ce qu'elle a à nettoyer de trois arguments.
Une autre stratégie de mise en œuvre est pour le compilateur ou peut-être l'éditeur de liens pour générer de l' __start
de la fonction (ou peu importe son nom), ou, au moins, sélectionnez-en un à partir de plusieurs pré-compilé des solutions de rechange. L'Information peut être stockée dans le fichier de l'objet sur lequel de la prise en charge des formes d' main
est utilisé. L'éditeur de liens pouvez regarder cette info, et de sélectionner la bonne version de la start-up module qui contient un appel à l' main
qui est compatible avec le programme de la définition. C implémentations n'ont généralement qu'un petit nombre de prises en charge des formes d' main
donc cette approche est faisable.
Les compilateurs pour le C99 langue de toujours avoir à traiter main
spécialement, dans une certaine mesure, à l'appui de la bidouille que si la fonction se termine sans un return
déclaration, le comportement est comme si return 0
ont été exécutés. Encore une fois, cela peut être traitée par une transformation du code. Le compilateur avis qu'une fonction appelée main
est en cours de compilation. Elle vérifie ensuite si la fin du corps est potentiellement accessible. Si oui, il insère return 0;