Voici les parties pertinentes de la norme. Voir mon explication ci-dessous le texte standard:
§6.9.2/2 Externe de l'objet de définitions
Une déclaration d'un identificateur d'un objet qui a de la portée du fichier sans un initialiseur, et sans stockage de classe rédacteur de devis ou avec la capacité de stockage de classe spécificateur de statique, constitue une tentative de définition. Si une unité de traduction contient un ou plusieurs provisoire définitions pour un identificateur, et l'unité de traduction ne contient pas de définition externe pour l'identifiant, puis le comportement est exactement comme si l'unité de traduction contient un fichier de la portée de la déclaration de l'identificateur, avec le type composite à compter de la fin de l'unité de traduction, avec un initialiseur égal à 0.
La norme ISO C99 §6.9/5 des définitions Externes
Une définition externe est une déclaration externe qui est aussi la définition d'une fonction (autre qu'une ligne de définition) ou un objet. Si un identificateur déclaré avec une liaison externe est utilisé dans une expression (autre que dans le cadre de l'opérande d'un opérateur sizeof dont le résultat est un entier constant), quelque part dans l'ensemble du programme, il doit y avoir exactement une définition externe de l'identificateur; sinon, il n'y aura plus qu'un seul.
Avec la version C, le 'g' variables globales sont "fusionnées" dans un, donc vous aurez seulement à la fin de la journée, qui est déclarée deux fois. C'est OK, en raison du temps lors de la extern n'était pas nécessaire, ou peut-être n'a pas de sorties. Donc, c'est pour l'historique et compatibilité des raisons de construire de l'ancien code. C'est un gcc extension pour cet héritage de la fonctionnalité.
Il rend fondamentalement gcc allouer de la mémoire pour une variable avec le nom "a", donc il peut y avoir plus d'une déclarations, mais une seule définition. C'est pourquoi le code ci-dessous ne fonctionnera pas, même avec gcc.
Il est également appelé tentative de définition. Il n'y a pas une telle chose avec C++, et c'est alors qu'il compile. C++ n'a pas de notion de provisoire de déclaration.
Une tentative de définition des données externes déclaration qui n'a pas de classe de stockage de prescripteur et le pas de l'initialiseur. Une tentative de définition est une définition complète si la fin de l'unité de traduction est atteint et aucune définition n'est apparu avec un initialiseur de l'identificateur. Dans ce cas, le compilateur réserve non initialisée espace pour l'objet défini.
Notez cependant que le code suivant ne compile pas, même avec gcc parce que c'est la tentative de définition de la déclaration de plus avec les valeurs attribuées:
dans le fichier "a.c/a.cpp"
int a = 1;
dans le fichier "b.c/b.cpp"
int a = 2;
int main() { return 0; }
Laissez-nous aller au-delà de cela avec d'autres exemples. Les instructions suivantes montrent normale définitions et de tentative de définitions. Remarque, statique d'en faire un peu la différence puisque c'est à la portée de fichier, et ne serait pas externe plus.
int i1 = 10; /* definition, external linkage */
static int i2 = 20; /* definition, internal linkage */
extern int i3 = 30; /* definition, external linkage */
int i4; /* tentative definition, external linkage */
static int i5; /* tentative definition, internal linkage */
int i1; /* valid tentative definition */
int i2; /* not legal, linkage disagreement with previous */
int i3; /* valid tentative definition */
int i4; /* valid tentative definition */
int i5; /* not legal, linkage disagreement with previous */
Pour plus de détails sur la page suivante:
http://c0x.coding-guidelines.com/6.9.2.html
Voir aussi ce billet de blog pour plus de détails:
http://ninjalj.blogspot.co.uk/2011/10/tentative-definitions-in-c.html