2010-09-03 22 views
3

J'essaie de m'adapter à Ada en C++ en utilisant des externes. Quelle est la différence entre ces deux implémentations?C++ Extern/Définitions multiples

Application A

namespace Ada 
{ 
    extern "C" 
    { 
     int getNumber(); 
     int index; 
     int value; 
    } 
} 

mise en œuvre B

namespace Ada 
{ 
    extern "C" 
    { 
     int getNumber(); 
    } 
    extern "C" int index; 
    extern "C" int value; 
} 

Les deux implémentations compiler très bien. Mais Impl-A ne parvient pas à lier, j'obtiens une erreur de définition multiple pour index et valeur. J'essaie juste de comprendre les différences.

Répondre

7

extern "C" ne véhicule que les conventions de liaison à utiliser le code dans le bloc extern "C". Tout ce qui est dans ce bloc sera lié comme s'il était pur c. Confusingly, extern int est totalement différent. Cela signifie que vous promettez qu'il existe un index nommé int réel et une valeur int réelle nommée quelque part, mais ils ne peuvent pas être trouvés ici. Dans votre implémentation-A les ints ne sont en fait pas extern dans le second sens - l'extern "C" implique seulement qu'ils fournissent une convention de liaison c stricte.

Même mot-clé mais utilisations totalement différentes, ce qui est regrettable car cela conduit à des problèmes étranges comme celui-ci. Les mélanger est légal (évidemment), mais ils ne se comportent pas comme leur nom l'indique.

EDIT

Voir la réponse de Charle pour la vraie définition de la bizarrerie extern tel que défini dans la norme C++.

+0

+1 Excellente explication – linuxuser27

+1

@Peter: J'ai pensé autant, mais cela ne dit toujours pas pourquoi la deuxième version du code fonctionne. – sbi

+0

+1 Merci. Cela répond à ma question. – Jerunh

3

Je ne sais pas pourquoi les secondes œuvres, mais vous voulez

namespace Ada 
{ 
    extern "C" 
    { 
     int getNumber(); 
     extern int index; 
     extern int value; 
    } 
} 

parce que vous voulez seulement déclare index et value, non définissent eux. (Voir this answer pour la différence.)

+0

deuxième fonctionne probablement parce que 'extern "C"' ne veut pas dire quoi que ce soit pour les variables, donc le ' "C"' est ignorée ? Juste une supposition. –

+0

Je pense que la question plus générale est de savoir pourquoi le paramètre extern ne définit pas extern pour tous. – linuxuser27

+1

@linuxuser: Il ne devrait pas. 'extern 'blah" T foo' indique simplement à l'éditeur de liens quelle convention de liaison suivre pour lier 'foo'. 'extern T bar', OTOH, dit au compilateur qu'il ne devrait pas s'inquiéter de l'existence de' bar', l'éditeur de liens trouvera (espérons-le) quelque part.Ce dernier utiliserait le lien "C++" (implicite). – sbi

7

A liaison spécificateur (c.-à-extern "C" ou extern "C++") appliqué à une séquence fermée de renfort de déclarations n'a pas d'effet si les déclarations jointes sont des définitions ou pas, mais un liaison spécificateur appliqué à une seule déclaration est traité comme un spécificateur extern afin de déterminer si une déclaration est également une définition. (7.5 par 7 de 03 C++)

Alors:

extern "C" { int a; } // a is declared and defined 

extern "C" int a; // a is just a declaration (as if extern int a;) 

extern "C" int a = 0; // a is a definition because of the initializer.