2010-03-27 10 views
5

Quelle est la différence entre les deux déclarations suivantes? Je pensais qu'ils étaient équivalents, mais le premier échantillon fonctionne, et le second ne fonctionne pas. Je veux dire qu'il compile et s'exécute, mais le code d'affichage bitmap est vide. Je ne l'ai pas encore franchi, mais ai-je oublié quelque chose d'évident? GUI_BITMAP est une structure simple décrivant un bitmap. C'est pour VC++ 2005, mais je pense qu'il échoue également dans VC++ 2008. Ma tête se grattant celui-ci ...Problème avec le mot clé extern en C++

Exemple 1:

extern "C" const GUI_BITMAP bmkeyA_cap_active; 
extern "C" const GUI_BITMAP bmkeyA_cap_inactive; 

Exemple 2:

extern "C" 
{ 
    const GUI_BITMAP bmkeyA_cap_active; 
    const GUI_BITMAP bmkeyA_cap_inactive; 
}; 

Edit: Plus a montré que explorer le deuxième exemple crée les struct, tandis que le premier fait référence à des structures externes. Le deuxième exemple devrait échouer à lier, car il existe deux variables à portée globale avec le même nom. Mais ce n'est pas le cas, il envoie une structure remplie à zéro au code d'affichage qui abandonne. Hmmm .....

Édition 2: L'exécution du même code par l'intermédiaire d'un autre compilateur (IAR) n'a pas réussi à compiler sur l'exemple 2, avec une erreur sur l'absence d'un constructeur par défaut. Donc je devine qu'il y a quelque chose de subtil sur le mot-clé "extern", les structures, et le C++ que je ne comprends pas. Si les choses dans la zone externe étaient fonctions les deux échantillons seraient identiques non?

Répondre

3

Votre éditeur de liens peut résoudre silencieusement les symboles dupliqués dans votre dos. Vous pouvez obtenir des bibliothèques statiques auprès d'un fournisseur et les lier à votre programme. Quelle est la solution pour la situation où vous avez deux bibliothèques de ce type et qu'elles définissent toutes deux un symbole commun? L'éditeur de lien résoudra cela, en choisissant l'une ou l'autre définition, et vous laissant traiter les retombées. Comment gérez-vous la phase de liaison de votre application? Vous pouvez obtenir de meilleurs résultats si vous liez directement les fichiers .o au lieu de les placer dans des bibliothèques intermédiaires avant de lier l'application finale.

This page de la documentation ARM décrit le problème bien - je pense comportement similaire se passe dans votre cas:

multiples définitions d'un symbole dans les différents objets de la bibliothèque ne sont pas nécessairement détectés. Une fois que l'éditeur de liens a trouvé une définition appropriée pour un symbole, il arrête de chercher les autres. En supposant que l'objet contenant le symbole en double n'est pas chargé pour d'autres raisons, aucune erreur ne se produira. Ceci est intentionnel et particulièrement utile dans certaines situations.

Edit: Plus la recherche a mis en place que ce problème est dû à cause d'une violation de la « One Definition Rule », et par conséquent le compilateur/éditeur de liens ne sont pas tenus de vous informer du problème. Cela rend votre question un doublon de this one.

+0

Merci pour la réponse, mais il n'y a pas d'objets de bibliothèque en cours d'utilisation ici, ce n'est que mon code, un mélange de C et C++. Ma question initiale demeure - quelle est la différence entre l'échantillon 1 et l'échantillon 2 - je pensais qu'ils devraient générer exactement le même code? Si les choses étaient des fonctions au lieu de structures - ce sont les mêmes choses, n'est-ce pas? – Jeff

+1

@Jeff, la réponse rapide à votre question est que non, ces deux ne sont pas les mêmes, ce qui explique pourquoi vous voyez des problèmes.Dans le second cas, vous modifiez uniquement les instructions dans '{}' pour utiliser les conventions de liaison de C. Dans le premier exemple, vous faites cela * plus * indiquant que les variables sont déclarées ailleurs. http://msdn.microsoft.com/en-us/library/0603949d(VS.80).aspx –

0

Le second exemple pourrait être équivalent au premier avec un extern supplémentaire devant le const. Dans le premier cas, le compilateur combine probablement les deux utilisations d'extern. Dans le second cas, je suppose que le compilateur ne fait pas tout le monde dans l'extern extern pour quelque raison que ce soit.