Doute liée à l’utilisation de mots-clés extern

Autant que je sache, le mot clé extern doit être utilisé pour la déclaration et aucune valeur ne peut être associée à la variable déclarée avec le mot clé extern. Mais supposons que j’écris une déclaration comme

extern int i = 10; 

Le compilateur doit-il signaler une erreur pour la même chose? J’ai vu des compilateurs être tolérants et ignorer cela? Pourquoi cela est-il ainsi? Que dit la norme ‘C’ à ce sujet?

EDIT: @All, Merci pour les réponses. J’ai un doute quand même. Supposons que j’ai la définition de cette variable sans le lien externe dans un autre fichier, disons ac et que j’ajoute cette instruction dans bc. Est-il toujours correct que le compilateur ne signale pas une erreur? Est-ce qu’il vient sous redefintion?

C’est une syntaxe valide. Il existe même un exemple essentiellement identique dans la norme C99. (Voir §6.9.2-4.)

Il est vrai que les exemples ne sont pas normatifs, mais je crois que c’était une syntaxe légale. Le compilateur émet souvent un avertissement, car il ne fait rien.

4 EXEMPLE 1

 int i1 = 1; // definition, external linkage static int i2 = 2; // definition, internal linkage extern int i3 = 3; // definition, external linkage int i4; // tentative definition, external linkage static int i5; // tentative definition, internal linkage int i1; // valid tentative definition, refers to previous int i2; // 6.2.2 renders undefined, linkage disagreement int i3; // valid tentative definition, refers to previous int i4; // valid tentative definition, refers to previous int i5; // 6.2.2 renders undefined, linkage disagreement extern int i1; // refers to previous, whose linkage is external extern int i2; // refers to previous, whose linkage is internal extern int i3; // refers to previous, whose linkage is external extern int i4; // refers to previous, whose linkage is external extern int i5; // refers to previous, whose linkage is internal 

Le code suivant;

 extern int i ; 

déclare une variable i, mais ne l’instancie pas. S’il n’est pas également défini dans la même unité de compilation, l’éditeur de liens tentera de le résoudre à partir des fichiers objects et des bibliothèques constituant le fichier exécutable final.

Cependant votre exemple:

 extern int i = 10 ; 

initialise l’object et doit donc aussi l’instancier. Dans ce cas, le mot-clé extern est redondant car l’object est initialisé dans la même unité de compilation (en fait, le même état). Cela équivaut à:

 extern int i ; // redundant int i = 10 ; 

Bien que, dans ce dernier exemple, le mot-clé extern soit redondant, il est exactement équivalent à ce que vous avez lorsqu’une variable globale est déclarée dans un fichier d’en-tête et instanciée dans un fichier source qui inclut également cet en-tête (comme il se doit, pour permettre au compilateur effectuer une vérification de type).

Vous pouvez tester ceci comme suit:

 extern int i ; int main() { i = 10 ; } 

Ce qui précède entraînera une erreur de l’éditeur de liens pour la variable non résolue i. Tandis que:

 extern int i = 10 ; int main() { i = 10 ; } 

reliera sans problème.

Le mot-clé extern indique que la variable donnée est allouée dans un module différent. Cela n’a rien à voir avec l’ access à cette variable. Il est parfaitement légal d’affecter d’affecter à une variable externe.

Le mot-clé extern pour but de donner à l’entité un lien externe . Qu’il soit utilisé dans une déclaration dans une définition ou une définition ne fait aucune différence. Il n’y a absolument aucune erreur dans le code que vous avez posté.

Si vous préférez y penser en termes “exportation / importation”, le mot clé extern appliqué à une déclaration non définissante signifie que nous importons une entité définie dans une autre unité de traduction. Lorsque le mot-clé extern appliqué à une définition , cela signifie que nous exportons cette entité pour qu’elle soit utilisée par d’autres unités de traduction. (Même s’il est intéressant de noter que “exportation / importation” n’est pas exactement une façon standard de penser le concept de couplage en C.)

La raison pour laquelle vous ne verrez pas très souvent le mot clé utilisé dans les définitions est que, dans C, les définitions d’étendue de fichier ont un lien externe par défaut. Donc écrire

 extern int i = 10; 

est valide, mais redondant, car il est équivalent à plain

 int i = 10; 

Cependant, de temps en temps, dans le code actuel, vous pouvez voir des personnes utiliser ce mot clé avec des déclarations de fonction et des définitions, même si cela est superflu également.

 extern void foo(int i); /* `extern` is superfluous */ ... extern void foo(int i) /* `extern` is superfluous */ { /* whatever */ }