47 votes

Le premier extrait ci-dessous est compilé, mais pas le second. Pourquoi?

L'extrait de code ci-dessous compile (démo):

struct A{ int i = 10; };

int main() {
    struct A{ int i = 20; };
    struct A;
    struct A a;
}

Mais ce n'est pas:

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct A a;
}

Je peux voir que la réponse est probablement donnée par ces paragraphes dans la Norme:

[de base.de recherche.elab]/2 et [de base.la portée.pdecl]/7.

Mais je ne sais vraiment pas comment en déduire les différents comportements indiqué ci-dessus à partir de ces deux paragraphes.

Notez que dans le premier exemple, l' struct A est pas déclaré d'abord dans le élaborées de type spécificateur struct A;, mais dans la définition de l' struct A en main().

Dans le deuxième exemple, l' struct A est également pas déclaré d'abord dans le élaborées de type spécificateur struct A;, mais dans la définition de l' struct Adans la portée globale.

67voto

Oktalist Points 2524

Chacun des exemples contient des déclarations de deux classes différentes, à la fois avec le nom de l' A.

Nous allons distinguer entre les classes en renommant l'un d'eux à l' B:

struct A{ int i = 10; };

int main() {
    struct B{ int i = 20; };
    struct B;
    struct B b;
}

Le ci-dessus est sémantiquement identique à votre premier exemple. La classe A n'est jamais utilisé.

struct A{ int i = 10; };

int main() {
    struct B;
    struct B b;
}

C'est sémantiquement identique à votre deuxième exemple. Vous êtes en train de créer un objet d'un type incomplète, l'avant-déclaration de la classe B.

Renommer B de retour à l' A ne change rien, car alors la déclaration d' A en main ombres de la déclaration de l'autre A au niveau global.

[de base.de recherche.elab]/2

Si le élaboré un type de prescripteur n'a pas imbriquée-nom-spécificateur, et [...] si la élaborées de type spécificateur apparaît dans une déclaration à la formule:

class-key attribute-specifier-seqopt identifier ;

le élaborées de type spécificateur est une déclaration qui introduit le nom de classe comme décrit dans [de base.la portée.pdecl].

Donc, struct A; est une déclaration qui introduit le nom de la classe dans le champ d'application de la déclaration. Ne peut en aucun cas se référer à une classe déclarée à l'extérieur de son champ d'application.

[de base.la portée.pdecl]/7

[ Note: d'Autres formes élaborées de type spécificateur de ne pas déclarer un nouveau nom [...] - la note de fin ]

Par implication, c'est une forme élaborée de type spécificateur déclare un nouveau nom.

44voto

François Andrieux Points 16034

Dans le deuxième exemple, la ligne struct A; est une déclaration anticipée pour une structure appelée dans la fonction principale du champ d'application. Cette structure sera préféré à l'global struct A. La ligne suivante définit une variable nommée a de type struct A. Depuis un struct A a été déclarée dans la fonction principale du champ d'application, c'est là où le compilateur de recherche pour la définition, il n'. Il ne parvient pas à en trouver un (commenté). Le premier exemple compile car il n'y a de définition dans le même champ d'application. L'exemple suivant permet de compiler cependant, car elle a précisé qu' A est dans l'espace de noms global :

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct ::A a;
}

5voto

theo2003 Points 427

Il ne compile pas car il ne peut pas trouver une définition de l'A.

int main() {
//    struct A{ int i = 20; };
      struct A;
      struct A a;
}

Le code ci-dessus est égal à votre premier exemple, comme le mondial de l'est de l'ombre à la locale A. Dans le deuxième exemple, Un n'a pas une définition. C'est juste un prototype. Les Prototypes sont censés être placés avant un bout de code qui a besoin d'une définition lorsque la définition est placé APRÈS le code qui en a besoin. Si le compliler ne peut pas trouver cette définition, il échoue parce qu'il ne sait pas ce qu'est censé être (la définition globale est masqué par le prototype, ce qui le fait être ignoré).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X