2012-01-27 1 views
1

Ce code produira erreur dans C++const et global

// Foo.cpp 
const int Foo = 99; 

// Main.cpp 
extern const int Foo; 
int main() 
{ 
    cout << Foo << endl; 
    return 0; 
}  

Raison donnée par beaucoup est const mondiale a une portée interne et est statique par défaut.

solution

à cette question est: -

//Foo.h 
    extern const int Foo; 

    // Foo.cpp 
    #include "Foo.h" 
    const int Foo = 99; 

    // Main.cpp 
    #include "Foo.h" 
    int main() 
    { 
     cout << Foo << endl; 
    } 

Je pensais que extern est utilisé pour indiquer que la mémoire compilateur pour le indentifer est déjà alloué quelque part dans d'autres fichiers.
En appliquant la même logique sur le code ci-dessus, peut-on expliquer ce qui se passe ici ou extern a une signification différente en C++?
enter link description here
Voir également cette page il gâte mes tous .. intuitions

Répondre

7

si nous devons déclarer qu'une constante globale (non static)? Comment extern aider à faire cela?

Un objet const déclaré avec le qualificateur extern a un lien externe.
Donc, si vous souhaitez utiliser un const sur plusieurs unités de traduction, ajoutez-y un qualificatif extern.

Alors qu'une variable globale a une liaison externe par défaut, pourquoi un global de const a une liaison interne par défaut?

Référence:
C++ 03 standard Annexe C Compatibilité C.1.2 Article 3: notions de base

Changement: Un nom de champ de fichier qui est explicitement déclaré const, et non explicitement déclaré extern, a une liaison interne, tandis qu'en C il aurait une liaison externe

Raison: Parce que les objets const peuvent être utilisés comme compile-time ue en C + +, cette fonction invite les programmeurs à fournir des valeurs d'initialisation explicites pour chaque const. Cette fonctionnalité permet à l'utilisateur de placer des objets const dans des fichiers d'en-tête inclus dans de nombreuses unités de compilation.


éviter la confusion en suivant une règle simple:

Par défaut liaison est externe pour les symboles non-const et statique (interne) pour les symboles const.

3

Un rappel rapide, de sorte qu'il est clair que nous parlons:

int const a;   // illegal 
int const a = 42;  // definition, internal linkage 
extern int const a;   // declaration, external linkage 
extern int const a = 42; // definition , external linkage 

Notez que sans const, les deux premières déclarations ci-dessus sont les deux définitions avec lien externe. C'est tout sauf orthogonal, et pas très intuitif, mais c'est ce que disent les règles actuelles.Le problème avec un lien externe const est qu'il peut y avoir seulement une définition d'un objet avec liaison externe, et avec une exception , seule la définition peut avoir un initialiseur. Cela signifie que pour un const avec liaison externe, la valeur réelle (nécessaire si le const doit être utilisé dans une expression constante) ne peut être visible que dans une unité de traduction . C'est probablement la motivation pour donner const liaison interne par défaut.

Bien sûr, cela ne cause pas de fin de problèmes avec les modèles, au moins en théorie; l'en-tête suivant a un comportement non défini si elle est y compris dans plus d'une unité de traduction:

#include <std::vector> 

int const fixedValue = 42; 
inline void insertFixedValue(std::vector<int>& dest) 
{ 
    dest.push_back(fixedValue); 
} 

La norme dit que ne doit pas seulement inline fonctions et modèles ont une séquence identique de jetons, mais que tous les symboles doit lier au même objet dans chaque unité de traduction, ou il y a violation de la règle de définition unique. Et puisque fixedValue n'a pas de lien externe , il y a une instance unique dans chaque unité de traduction. (Il y a une exception si le symbole fait référence à un objet constet il y a une lvalue immédiate à la conversion rvalue. Depuis std::vector<int>::push_back prend son argument par référence, cependant, il n'y a pas lvalue immédiatement à la conversion rvalue, et nous obtenons un comportement non défini )

et bien sûr, tout le monde avec un modèle.

template <int& r> ... 

instanciation avec fixedValue non plus.

La raison de la liaison interne est, bien sûr, historique. Aujourd'hui, compilateurs doit être capable de supporter des choses comme:

struct X 
{ 
    static int const a = 42; // declaration!!!, external linkage 
}; 

et toutes sortes de définitions en double pour les fonctions. Il serait relativement trivial d'étendre les règles permettant initializers sur une déclaration dans une classe à des variables à périmètre d'espace de noms, pour donner quelque chose comme:

int const a;    // illegal 
int const a = 42;   // definition, external linkage 
extern int const a;   // declaration, external linkage 
extern int const a = 42; // declaration, external linkage 

Cela rétablirait orthogonalité (même s'il fallait taper supplémentaire) . il casserait également presque tout le code existant.

Une autre alternative serait de traiter const définitions variables exactement comme modèles de fonction sont traités aujourd'hui: vous pouvez avoir plusieurs définitions , mais ils doivent tous être identiques. Cela éviterait probablement la plupart des casse de code, sinon tous.

+0

'extern const a; 'n'est pas valide C++, je ne pense pas. Vous avez besoin de quelque chose comme 'extern const' ** int ** 'a;' Vous avez tort dans votre premier bloc en surbrillance, mais correct dans le dernier. –

+0

@RobertCrovella Je ne pense pas que ce soit encore valide C, aujourd'hui (et c'est certainement une mauvaise pratique si elle est valide). Je l'ai réparé. –