La section $ 3.6.1 / 1 du standard C ++ lit,
Un programme doit contenir une fonction globale appelée main , qui est le début désigné du programme.
Considérons maintenant ce code,
int square(int i) { return i*i; }
int user_main()
{
for ( int i = 0 ; i < 10 ; ++i )
std::cout << square(i) << endl;
return 0;
}
int main_ret= user_main();
int main()
{
return main_ret;
}
Cet exemple de code fait ce que je compte faire, c'est-à-dire imprimer le carré des nombres entiers de 0 à 9, avant d' entrer dans la main()
fonction qui est censée être le "début" du programme.
Je l'ai également compilé avec l' -pedantic
option, GCC 4.5.0. Cela ne donne aucune erreur, pas même d'avertissement!
Donc ma question est,
Ce code est-il vraiment conforme à la norme?
S'il est conforme à la norme, cela n'invalide-t-il pas ce que dit la norme? main()
n'est pas le début de ce programme! user_main()
exécuté avant le main()
.
Je comprends que pour initialiser la variable globale main_ret
, le use_main()
exécute en premier, mais c'est une chose complètement différente; le point est que, il n'annule la déclaration citée $ 3.6.1 / 1 de la norme, comme n'est pas le début du programme; c'est en fait la fin de ce programme!main()
ÉDITER:
Comment définissez-vous le mot «commencer»?
Cela se résume à la définition de l'expression «début du programme» . Alors, comment le définissez-vous exactement?
main()
comme "début du programme"static
une durée de stockage, et en tant que tels, ces objets appartenant à différentes unités de traduction peuvent être initialisés dans n'importe quel ordre (car l'ordre n'est pas spécifié par la norme). Je ne sais pas si cela répond à votre question, même si c'est ce que je pourrais dire dans le contexte de ce sujet.Vous ne lisez pas correctement la phrase.
La norme définit le mot «début» aux fins du reste de la norme. Il ne dit pas qu'aucun code ne s'exécute avant d'
main
être appelé. Il dit que le début du programme est considéré comme à la fonctionmain
.Votre programme est conforme. Votre programme n'a "démarré" qu'au démarrage de main. Le constructeur est appelé avant que votre programme "démarre" selon la définition de "start" dans la norme, mais cela n'a guère d'importance. Beaucoup de code est exécuté avant
main
est jamais appelé dans tous les programmes, non seulement cet exemple.Pour les besoins de la discussion, votre code constructeur est exécuté avant le «démarrage» du programme, ce qui est entièrement conforme à la norme.
la source
Votre programme ne sera pas lié et ne fonctionnera donc pas à moins qu'il n'y ait un fichier main. Cependant main () ne provoque pas le démarrage de l'exécution du programme car les objets au niveau du fichier ont des constructeurs qui s'exécutent au préalable et il serait possible d'écrire un programme entier qui exécute sa durée de vie avant que main () soit atteint et de laisser main lui-même avoir un corps vide.
En réalité, pour appliquer cela, vous devez avoir un objet construit avant main et son constructeur pour appeler tout le flux du programme.
Regarde ça:
Le flux de votre programme découlerait effectivement de
Foo::Foo()
la source
Vous avez également marqué la question comme "C", alors, en parlant strictement de C, votre initialisation devrait échouer selon la section 6.7.8 "Initialisation" de la norme ISO C99.
La plus pertinente dans ce cas semble être la contrainte # 4 qui dit:
Donc, la réponse à votre question est que le code n'est pas conforme à la norme C.
Vous voudriez probablement supprimer la balise "C" si vous n'étiez intéressé que par la norme C ++.
la source
La section 3.6 dans son ensemble est très claire sur l'interaction
main
et les initialisations dynamiques. Le «début désigné du programme» n'est utilisé nulle part ailleurs et est simplement descriptif de l'intention générale demain()
. Cela n'a aucun sens d'interpréter cette expression d'une manière normative qui contredit les exigences plus détaillées et plus claires de la Norme.la source
Le compilateur doit souvent ajouter du code avant main () pour être conforme au standard. Parce que la norme spécifie que l'initalisation des globals / statiques doit être effectuée avant l'exécution du programme. Et comme mentionné, il en va de même pour les constructeurs d'objets placés à portée de fichier (globals).
Ainsi, la question initiale est pertinente pour C, car dans un programme C vous auriez toujours l'initialisation globale / statique à faire avant que le programme puisse être démarré.
Les standards supposent que ces variables sont initialisées par "magie", car elles ne disent pas comment elles doivent être définies avant l'initialisation du programme. Je pense qu'ils considéraient cela comme quelque chose qui sortait du cadre d'une norme de langage de programmation.
Edit: Voir par exemple ISO 9899: 1999 5.1.2:
La théorie derrière la façon dont cette "magie" devait être faite remonte à la naissance de C, quand c'était un langage de programmation destiné à être utilisé uniquement pour le système d'exploitation UNIX, sur des ordinateurs basés sur la RAM. En théorie, le programme serait capable de charger toutes les données pré-initialisées du fichier exécutable dans la RAM, en même temps que le programme lui-même était téléchargé dans la RAM.
Depuis lors, les ordinateurs et les systèmes d'exploitation ont évolué et C est utilisé dans un domaine beaucoup plus large que prévu à l'origine. Un système d'exploitation PC moderne a des adresses virtuelles, etc., et tous les systèmes embarqués exécutent du code à partir de la ROM, pas de la RAM. Il existe donc de nombreuses situations dans lesquelles la RAM ne peut pas être réglée "automatiquement".
De plus, le standard est trop abstrait pour savoir quoi que ce soit sur les piles et la mémoire de processus, etc. Ces choses doivent être faites aussi, avant que le programme ne démarre.
Par conséquent, pratiquement tous les programmes C / C ++ ont du code init / "copy-down" qui est exécuté avant l'appel de main, afin de se conformer aux règles d'initialisation des standards.
Par exemple, les systèmes embarqués ont généralement une option appelée "démarrage non conforme ISO" où toute la phase d'initialisation est ignorée pour des raisons de performances, puis le code démarre en fait directement à partir de main. Mais ces systèmes ne sont pas conformes aux normes, car vous ne pouvez pas vous fier aux valeurs init des variables globales / statiques.
la source
Votre "programme" renvoie simplement une valeur d'une variable globale. Tout le reste est du code d'initialisation. Ainsi, la norme tient - vous avez juste un programme très simple et une initialisation plus complexe.
la source
main () est une fonction utilisateur appelée par la bibliothèque d'exécution C.
voir aussi: Éviter le principal (point d'entrée) dans un programme C
la source
Cela ressemble à un chipotage sémantique anglais. L'OP fait d'abord référence à son bloc de code comme "code" et plus tard comme "programme". L'utilisateur écrit le code, puis le compilateur écrit le programme.
la source
main est appelée après l'initialisation de toutes les variables globales.
Ce que la norme ne spécifie pas, c'est l'ordre d'initialisation de toutes les variables globales de tous les modules et bibliothèques liées statiquement.
la source
Oui, main est le "point d'entrée" de chaque programme C ++, à l'exception des extensions spécifiques à l'implémentation. Même ainsi, certaines choses se produisent avant main, notamment l'initialisation globale comme pour main_ret.
la source