2009-11-24 5 views
1

Comment se comporte l'exemple suivant d'utilisation du spécificateur extern.Utilisation du spécificateur de classe de stockage "extern" dans C

Nous avons une variable globale int x à la fois dans les fichiers un.c et deux.c Nous voulons utiliser dans trois.c ont donc déclaré cette variable dans trois.c comme

extern int x;

Que se passerait-il lorsque nous compilions et lions ces fichiers?

Ma réponse est: la compilation de tous ces fichiers devrait réussir, cependant l'éditeur de liens devrait signaler une erreur lors de la liaison, en raison de plusieurs déclarations de x. Y aurait-il une différence de comportement en C++?

Est-ce un moyen de se référer à int x (dans trois.c) simultanément à partir des deux fichiers, en C et C++. En C++, je suppose que nous pouvons utiliser des espaces de noms pour y parvenir. Droite?

+0

La déclaration de la variable devrait être en tête, et l'en-tête doit être utilisé dans chaque fichier qui fait référence à la variable, et il doit être utilisé dans le seul fichier (seul, solitaire) qui définit réellement la variable. Si vous essayez de lier du code avec deux définitions d'une seule variable globale, vous êtes en dehors du comportement standard et dans les extensions communes documentées dans la norme (Annexe J). –

+0

Voir aussi: http://stackoverflow.com/questions/1433204/what-are-extern-variables-in-c/ –

Répondre

6

Par défaut, les variables globales ont linkage externe, ce qui signifie qu'elles peuvent être utilisées par d'autres fichiers sources (ou «unités de traduction»). Si vous déclarez plutôt vos variables globales avec le mot-clé static, elles auront liaison interne, ce qui signifie qu'elles ne seront pas utilisables par d'autres fichiers source.

Pour les variables avec liaison externe, vous ne pouvez pas avoir plusieurs variables avec le même nom, ou l'éditeur de liens va se plaindre. Vous pouvez cependant avoir deux variables avec le même nom, à condition qu'au moins l'une d'entre elles ait un lien interne, et bien sûr vous ne pouvez pas les référencer toutes les deux dans le même fichier source. Une déclaration extern indique simplement au compilateur "voici le nom d'une variable avec une liaison externe définie dans une autre unité de traduction", ce qui vous permet de vous référer à cette variable.

C++ est exactement le même, sauf pour l'ajout d'espaces de noms. Si des variables globales sont placées dans un espace de noms, elles peuvent avoir le même nom sans erreurs de liens, à condition qu'elles se trouvent dans des espaces de noms différents. Bien sûr, toutes les références à ces variables doivent alors se référer au nom complet namespace::var_name, ou utiliser une déclaration using pour établir un contexte d'espace de noms local.

C++ a également des espaces de noms anonymes, qui sont entièrement équivalents à l'utilisation du mot clé static pour les variables globales dans C: toutes les variables et fonctions déclarées dans un espace de noms anonyme ont une liaison interne.

Donc, pour répondre à votre question initiale, vous avez raison - la compilation réussirait, mais relier échouerait, en raison de multiples définitions de la x variables avec une liaison externe (en particulier, des unités de traduction one.c et two.c).

De three.c, il est impossible de se référer simultanément aux deux variables x. Vous devrez renommer x dans un ou deux modules, ou de passer à C++ et de mettre au moins un x intérieur d'un espace de noms.

+0

Excellente réponse Adam. Merci. – Ankur

+0

Comment l'éditeur de liens sait-il quelles "unités de traduction" rechercher la variable externe, est-ce un paramètre ou quelque chose? – marchinram

+0

@marchinram: L'éditeur de liens sait que, au moment de la liaison, l'éditeur de liens charge en une seule fois tous les fichiers objets et toutes les bibliothèques en cours de liaison, puis les parcourt et corrige les références externes. S'il trouve 'var_name' dans' a.o' et voit ensuite que 'b.o' fait référence à' var_name', il va corriger les espaces réservés dans 'b.o' pour pointer vers le vrai' var_name' dans 'a.o'. Si 'var_name' n'existe nulle part, c'est une erreur (généralement appelée" référence externe non résolue "ou quelque chose comme ça). –

0

Pour éviter de générer des symboles en double, vous devez déclarer extern int x; dans un seul fichier d'en-tête (un fichier .h), et ensuite tous les fichiers .c qui utiliseront x #include que tête de fichier et définir ou initialiser int x; dans un des fichiers .c.

+1

C'est, en supposant qu'il ne devrait y avoir une variable. Je pense que l'OP veut deux variables globales avec le même nom, ce qui est plutôt stupide, et je suppose une simplification théorique d'un design défectueux plus complexe. –

+0

Chris ce n'est pas trop rare dans le code de production où vous finissez par utiliser le code d'un fournisseur tiers ou plusieurs équipes travaillant sur un produit avec plusieurs sous-systèmes. – Ankur

+1

Le problème est le même: vous avez deux variables globales avec un lien externe avec le même nom, et vous devez utiliser les deux. Et la réponse est, en C, vous ne pouvez pas. En C++ vous pouvez avec des espaces de noms, mais alors ils n'ont pas vraiment le même nom, alors pourquoi ne pas leur donner de nouveaux noms et ne pas avoir à se soucier de la dispute en premier lieu? –

0

Vous pourriez être intéressé par les réponses à this question.

Résumé: l'éditeur de liens peut ou non ne pas pouvoir lier le fichier. Cela dépend de l'initialisation de la variable. Il échouera définitivement si la variable a des initialisations différentes dans différents fichiers.

1

En C, vous pouvez le faire:

// one.c 
static int x; 
int *one_x = &x; 

// two.c 
static int x; 
int *two_x = &x; 

// three.c 
extern int *one_x; 
extern int *two_x; 

Maintenant, vous pouvez vous référer clairement à la x dans le fichier ou le one.cx dans le fichier two.c à partir du fichier three.c.

Cependant, cela pourrait être un peu plus d'effort que cela vaut la peine. Peut-être devriez-vous trouver des noms plus descriptifs pour vos variables globales au lieu de vous contenter de moyens théoriques pour contourner l'unique espace de noms global de C.

0

Rappelez-vous que vous ne pouvez PAS extern une variable statique globale .. !!

Questions connexes