Je demande parce que mon compilateur semble le penser, même si ce n'est pas le cas.
echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall
Clang n'émet aucun avertissement ou erreur avec ceci, et gcc émet seulement l'avertissement doux:, 'main' is usually a function [-Wmain]
mais seulement lorsqu'il est compilé en C. Spécifier a -std=
ne semble pas avoir d'importance.
Sinon, il compile et lie très bien. Mais à l'exécution, il se termine immédiatement avec SIGBUS
(pour moi).
Lire les (excellentes) réponses à Que devrait retourner main () en C et C ++? et un rapide grep à travers les spécifications du langage, il me semblerait certainement qu'une fonction principale est nécessaire. Mais le verbiage de gcc -Wmain
(«main» est généralement une fonction) (et le manque d'erreurs ici) semble suggérer le contraire.
Mais pourquoi? Y a-t-il une utilisation étrange ou «historique» pour cela? Quelqu'un sait ce qui donne?
Mon point, je suppose, est que je pense vraiment que cela devrait être une erreur dans un environnement hébergé, hein?
gcc -std=c99 -pedantic ...
-pedantic
ou aucun-std
. Mon systèmec99
compile également cela sans avertissement ni erreur ...main
, qui ne fonctionnera probablement pas. Si vous initialisez main avec la «bonne» valeur, il peut en fait retourner ...main
)main=195;
Réponses:
Puisque la question porte deux balises en C et C ++, le raisonnement pour C ++ et C serait différent:
xyz
et une fonction globale autonomexyz(int)
. Cependant, le nommain
n'est jamais mutilé.C'est ce qui se passe ici: l'éditeur de liens s'attend à trouver un symbole
main
, et il le fait. Il «connecte» ce symbole comme s'il s'agissait d'une fonction, car il ne sait pas mieux. La partie de la bibliothèque d'exécution qui passe le contrôle à l'main
éditeur de liens demandemain
, donc l'éditeur de liens lui donne un symbolemain
, laissant la phase de liaison se terminer. Bien sûr, cela échoue à l'exécution, car cemain
n'est pas une fonction.Voici une autre illustration du même problème:
fichier xc:
fichier yc:
compilation:
Cela compile, et il s'exécuterait probablement, mais ce comportement n'est pas défini, car le type du symbole promis au compilateur est différent du symbole réel fourni à l'éditeur de liens.
En ce qui concerne l'avertissement, je pense que c'est raisonnable: C vous permet de créer des bibliothèques qui n'ont pas de
main
fonction, donc le compilateur libère le nommain
pour d'autres utilisations si vous devez définir une variablemain
pour une raison inconnue.la source
main
n'est pas soumis à la modification des noms (semble-t-il) en C ++, qu'il s'agisse ou non d'une fonction.main
comme autre chose qu'une fonction. La réponse offre une explication pour les deux parties.main
n'est pas un mot réservé , il est juste un identifiant prédéfini (commecin
,endl
,npos
...), vous pouvez déclarer une variable appeléemain
, initialiser et imprimer sa valeur.Bien sûr:
main()
fonction (bibliothèques).ÉDITER
Quelques références:
main
n'est pas un mot réservé (C ++ 11):C ++ 11 - [basic.start.main] 3.6.1.3
Mots réservés dans les langages de programmation .
Les mots réservés peuvent ne pas être redéfinis par le programmeur, mais les prédéfinis peuvent souvent être remplacés dans une certaine mesure. C'est le cas de
main
: il existe des portées dans lesquelles une déclaration utilisant cet identifiant redéfinit sa signification.la source
main()
fonction, mais vous ne pouvez pas la lier en tant que programme. Ce qui se passe ici, c'est qu'un programme "valide" est lié sansmain()
, juste unmain
.cin
etendl
ne sont pas dans l'espace de noms par défaut - ils sont dans l'std
espace de noms.npos
est membre destd::basic_string
.main
est réservé en tant que nom global. Aucune des autres choses que vous avez mentionnées, nimain
n'est prédéfinie.main
est autorisé à être. C ++ dit "Une implémentation ne doit pas prédéfinir la fonction principale" et C dit "L'implémentation ne déclare aucun prototype pour cette fonction."Un programme
int main;
C / C ++ valide est-il?Ce qu'est un programme C / C ++ n'est pas tout à fait clair.
Un
int main;
programme C valide est-il?Oui. Une implémentation autonome est autorisée à accepter un tel programme.
main
n'a pas besoin d'avoir une signification particulière dans un environnement autonome.Il n'est pas valide dans un environnement hébergé.
Un
int main;
programme C ++ est -il valide?Idem.
Pourquoi ça plante?
Le programme n'a pas à avoir de sens dans votre environnement. Dans un environnement autonome, le démarrage et l'arrêt du programme, ainsi que la signification de
main
, sont définis par l'implémentation.Pourquoi le compilateur me prévient-il?
Le compilateur peut vous avertir de tout ce qui lui plaît, tant qu'il ne rejette pas les programmes conformes. D'un autre côté, l'avertissement est tout ce qui est nécessaire pour diagnostiquer un programme non conforme. Étant donné que cette unité de traduction ne peut pas faire partie d'un programme hébergé valide, un message de diagnostic est justifié.
Est-ce
gcc
un environnement autonome ou s'agit-il d'un environnement hébergé?Oui.
gcc
documente l'-ffreestanding
indicateur de compilation. Ajoutez-le et l'avertissement disparaît. Vous voudrez peut-être l'utiliser lors de la construction, par exemple, de noyaux ou de micrologiciels.g++
ne documente pas un tel drapeau. Le fournir semble n'avoir aucun effet sur ce programme. Il est probablement prudent de supposer que l'environnement fourni par g ++ est hébergé. L'absence de diagnostic dans ce cas est un bug.la source
C'est un avertissement car il n'est pas techniquement interdit. Le code de démarrage utilisera l'emplacement du symbole "main" et y sautera avec les trois arguments standard (argc, argv et envp). Il ne le fait pas, et au moment du lien ne peut pas vérifier qu'il s'agit bien d'une fonction, ni même qu'il a ces arguments. C'est aussi pourquoi int main (int argc, char ** argv) fonctionne - le compilateur ne connaît pas l'argument envp et il se trouve juste qu'il n'est pas utilisé, et c'est le nettoyage de l'appelant.
Pour plaisanter, vous pourriez faire quelque chose comme
sur une machine x86 et, en ignorant les avertissements et autres choses similaires, il ne se contentera pas de compiler mais fonctionnera aussi.
Quelqu'un a utilisé une technique similaire à celle-ci pour écrire un exécutable (en quelque sorte) qui s'exécute directement sur plusieurs architectures - http://phrack.org/issues/57/17.html#article . Il a également été utilisé pour gagner l'IOCCC - http://www.ioccc.org/1984/mullender/mullender.c .
la source
int main __attribute__ ((section (".text")))= 0xC3C3C3C3;
Est-ce un programme valide?
Non.
Ce n'est pas un programme car il n'a pas de parties exécutables.
Est-il valide de compiler?
Oui.
Peut-il être utilisé avec un programme valide?
Oui.
Tout le code compilé ne doit pas nécessairement être exécutable pour être valide. Des exemples sont des bibliothèques statiques et dynamiques.
Vous avez effectivement construit un fichier objet. Ce n'est pas un exécutable valide, mais un autre programme peut créer un lien vers l'objet
main
dans le fichier résultant en le chargeant au moment de l'exécution.Cela devrait-il être une erreur?
Traditionnellement, C ++ permet à l'utilisateur de faire des choses qui peuvent sembler ne pas avoir d'utilisation valable mais qui correspondent à la syntaxe du langage.
Je veux dire que bien sûr, cela pourrait être reclassé comme une erreur, mais pourquoi? À quoi cela servirait-il que l'avertissement ne le fasse pas?
Tant qu'il y a une possibilité théorique que cette fonctionnalité soit utilisée dans le code réel, il est très peu probable que le fait d'avoir un objet non fonctionnel appelé
main
entraînerait une erreur selon le langage.la source
main
. Comment un programme valide, qui doit avoir une fonction visible de l'extérieur nomméemain
, peut-il y être lié?main
fonction.int main;
définition ne sera pas visible.Je voudrais ajouter aux réponses déjà données en citant les normes linguistiques actuelles.
Est 'int main;' un programme C valide?
Réponse courte (mon avis): uniquement si votre implémentation utilise un "environnement d'exécution autonome".
Toutes les citations suivantes de C11
5. Environnement
5.1.2 Environnements d'exécution
5.1.2.1 Environnement autonome
5.1.2.2 Environnement hébergé
5.1.2.2.1 Démarrage du programme
À partir de ceux-ci, on observe ce qui suit:
Dans un environnement d'exécution autonome, je dirais qu'il s'agit d'un programme valide qui ne permet pas le démarrage, car il n'y a pas de fonction présente pour cela comme requis dans 5.1.2. Dans un environnement d'exécution hébergé, alors que votre code introduit un objet nommé main , il ne peut pas fournir de valeur de retour, je dirais donc que ce n'est pas un programme valide dans ce sens, bien que l'on puisse également argumenter comme avant que si le programme ne l'est pas destiné à être exécuté (on peut vouloir fournir des données uniquement par exemple), alors cela ne permet tout simplement pas de faire cela.
Est 'int main;' un programme C ++ valide?
Réponse courte (mon avis): uniquement si votre implémentation utilise un "environnement d'exécution autonome".
Citation de C ++ 14
3.6.1 Fonction principale
Ici, contrairement à la norme C11, moins de restrictions s'appliquent à l'environnement d'exécution autonome, car aucune fonction de démarrage n'est mentionnée du tout, tandis que pour un environnement d'exécution hébergé, le cas est à peu près le même que pour C11.
Encore une fois, je dirais que pour le cas hébergé, votre code n'est pas un programme C ++ 14 valide, mais je suis sûr que c'est pour le cas autonome.
Étant donné que ma réponse ne prend en compte que l' environnement d' exécution , je pense que la réponse de dasblinkenlicht entre en jeu, car la modification des noms se produisant dans l' environnement de traduction se produit à l'avance. Ici, je ne suis pas si sûr que les citations ci-dessus soient observées de manière aussi stricte.
la source
L'erreur est la vôtre. Vous n'avez pas spécifié de fonction nommée
main
qui renvoie unint
et avez essayé d'utiliser votre programme dans un environnement hébergé.Supposons que vous ayez une unité de compilation qui définit une variable globale nommée
main
. Cela pourrait bien être légal dans un environnement autonome car ce qui constitue un programme est laissé à la mise en œuvre dans des environnements autonomes.Supposons que vous ayez une autre unité de compilation qui définit une fonction globale nommée
main
qui renvoie unint
et ne prend aucun argument. C'est exactement ce dont un programme dans un environnement hébergé a besoin.Tout va bien si vous n'utilisez que la première unité de compilation dans un environnement autonome et n'utilisez que la seconde dans un environnement hébergé. Et si vous utilisez les deux dans un même programme? En C ++, vous avez enfreint la règle de définition unique. C'est un comportement indéfini. En C, vous avez violé la règle qui veut que toutes les références à un seul symbole soient cohérentes; s'ils ne le sont pas, c'est un comportement indéfini. Un comportement indéfini est un "sortez de prison, gratuitement!" carte aux développeurs d'une implémentation. Tout ce qu'une implémentation fait en réponse à un comportement indéfini est conforme à la norme. L'implémentation n'a pas à avertir, encore moins à détecter, un comportement non défini.
Et si vous n'utilisez qu'une seule de ces unités de compilation, mais que vous utilisez la mauvaise (ce que vous avez fait)? En C, la situation est claire. Le fait de ne pas définir la fonction
main
dans l'un des deux formulaires standard dans un environnement hébergé est un comportement indéfini. Supposons que vous ne définissiez pasmain
du tout. Le compilateur / éditeur de liens n'a rien à dire à propos de cette erreur. Qu'ils se plaignent est une gentillesse en leur nom. Que le programme C compilé et lié sans erreur est de votre faute, pas de celle du compilateur.C'est un peu moins clair en C ++ car l'échec de la définition de la fonction
main
dans un environnement hébergé est une erreur plutôt qu'un comportement indéfini (en d'autres termes, il doit être diagnostiqué). Cependant, la règle de définition unique en C ++ signifie que les éditeurs de liens peuvent être plutôt stupides. Le travail de l'éditeur de liens est de résoudre les références externes, et grâce à la règle d'une définition unique, l'éditeur de liens n'a pas besoin de savoir ce que signifient ces symboles. Vous avez fourni un symbole nommémain
, l'éditeur de liens s'attend à voir un symbole nommémain
, donc tout va bien en ce qui concerne l'éditeur de liens.la source
Pour C jusqu'à présent, c'est le comportement défini par l'implémentation.
Comme le dit l'ISO / CEI9899:
la source
Non, ce n'est pas un programme valide.
Pour C ++, cela a été récemment explicitement rendu mal formé par le rapport de défaut 1886: Lien de langage pour main () qui dit:
et une partie de la résolution comprenait le changement suivant:
Nous pouvons trouver ce libellé dans le dernier projet de norme C ++ N4527 qui est le projet C ++ 1z.
Les dernières versions de clang et gcc font maintenant une erreur ( voyez-le en direct ):
Avant ce rapport de défaut, il s'agissait d'un comportement non défini qui ne nécessite pas de diagnostic. D'un autre côté, un code mal formé nécessite un diagnostic, le compilateur peut en faire un avertissement ou une erreur.
la source
main()
.) Je comprends la justification de l'interdictionmain()
d'avoir une spécification de lien explicite, mais je ne comprends pas qu'il soit obligatoire d'main()
avoir un lien C ++ . Bien sûr , la norme ne concerne pas directement l' adresse comment gérer la liaison ABI / nom mutiler, mais dans la pratique ( par exemple, avec ABI Itanium) ce serait mutilermain()
à_Z4mainv
. Qu'est-ce que je rate?