Implémentation de variable globale

Quand j’écris le programme suivant:

fichier 1:

#include  int global; void print_global1() { printf("%p\n", &global); } 

fichier 2:

 #include  char global; void print_global2() { printf("%p\n", &global); } 

fiche 3:

 void print_global1(); void print_global2(); int main() { print_global1(); print_global2(); return 0; } 

sortie:

 $ ./a.out 0x804a01c 0x804a01c 

Voici ma question:

  • Pourquoi l’éditeur de liens implémentant “int global” et “char global” en tant que même variable globale:
  • Comment se fait-il que le compilateur ne se plaint pas (pas le plus petit avertissement avec -Wall -Wextra -ansi …)
  • Comment la taille de la variable globale est gérée (les tailles de int et char sont différentes)

PS: La deuxième question concerne l’architecture et le compilateur, prenons donc gcc ou Visual C ++ (pour C) avec la taille int 32 bits.

EDIT: CECI N’EST PAS UNE QUESTION POUR C ++ MAIS POUR C!

J’utilise la version 4.4.1 de gcc et sur Ubuntu 9.10, voici la sortie de la console de compilation:

 $ ls global_data1.c global_data2.c global_data.c $ gcc -Wall -Wextra -ansi global_data*.c $ ./a.out 0x804a01c 0x804a01c or $ gcc -Wall -Wextra -ansi -c global_data*.c $ gcc -Wall -Wextra -ansi global_data*.o $ ./a.out 0x804a01c 0x804a01c 

    gcc ne rapporte aucune erreur / avertissement. Mais g++ fait.

    MODIFIER:

    On dirait que C autorise les définitions provisoires pour une variable.

    Dans votre cas, les deux définitions globales sont provisoires et dans ce cas, la première vue par l’éditeur de lien est choisie.

    Changez votre fichier2 en:

     char global = 1; // no more tentative...but explicit. 

    Maintenant, si vous comstackz comme auparavant, la tentative de définition de def dans fichier1 sera ignorée.

    Rendre explicites la définition par:

     int global = 1; // in file1 char global = 1; // in file2 

    maintenant, aucun des deux ne peut être ignoré et nous obtenons l’erreur de définition multiple.

    Cela a à voir avec quelque chose appelé “définition provisoire” en C. Premièrement, si vous affectez à global dans file1 et file2, vous obtiendrez une erreur en C. C’est parce que global n’est plus défini provisoirement dans file1 et file2, il est vraiment défini.

    De la norme C (mon emphase):

    La déclaration d’un identifiant pour un object ayant une scope de fichier sans initialiseur , et sans spécificateur de classe de stockage ou avec le spécificateur de classe de stockage static, constitue une définition provisoire . Si une unité de traduction contient une ou plusieurs définitions provisoires pour un identificateur et que l’unité de traduction ne contient aucune définition externe pour cet identificateur, le comportement est exactement comme si l’unité de traduction contenait une déclaration de la scope du fichier de cet identificateur, avec le type composite as de la fin de l’unité de traduction, avec un initialiseur égal à 0.

    Pour votre cas, “unité de traduction” (en gros) chaque fichier source.

    À propos des “types composites”:

    Pour un identifiant avec une liaison interne ou externe déclarée dans une étendue dans laquelle une déclaration préalable de cet identifiant est visible, si la déclaration précédente spécifie une liaison interne ou externe, le type de l’identifiant dans la déclaration ultérieure devient le type composite.

    Pour plus d’informations sur les définitions provisoires, voir cette question et ses réponses .

    Il semble que dans votre cas, le comportement devrait être indéfini, car global est défini à la fin des unités de traduction. Vous obtenez donc deux définitions de global et, pire encore, elles sont différentes. On dirait que l’éditeur de liens par défaut ne s’en plaint pas.

    GNU ld a une option appelée --warn-common , qui vous avertit de plusieurs définitions provisoires (le symbole commun est le nom du linker pour les variables définies provisoirement):

     $ gcc -Wl,--warn-common file*.c /tmp/ccjuPGcq.o: warning: common of `global' overridden by larger common /tmp/ccw6nFHi.o: warning: larger common is here 

    Du manuel :

    S’il n’y a que (un ou plusieurs) symboles communs pour une variable, celle-ci est enregistrée dans la zone de données non initialisée du fichier de sortie. L’éditeur de liens fusionne plusieurs symboles communs pour la même variable en un seul symbole. Si elles sont de tailles différentes, il choisit la plus grande taille. L’éditeur de liens transforme un symbole commun en une déclaration, s’il existe une définition de la même variable.

    L’option --warn-common peut produire cinq types d’avertissements. Chaque avertissement consiste en une paire de lignes: la première décrit le symbole que l’on vient de rencontrer et la seconde décrit le symbole précédent rencontré avec le même nom. L’un des deux symboles, ou les deux, sera un symbole commun.

    L’éditeur de liens permet d’avoir des données externes en double comme ceci (bien que je sois surpris que les différents types ne posent pas de problème). Le fichier que vous obtenez dépend de l’ordre de vos fichiers object sur votre ligne de commande de lien.

    Quel compilateur utilisez-vous. Quelle est la plateforme? Avec g ++ je reçois

     /tmp/cc8Gnf4h.o:(.bss+0x0): multiple definition of `global' /tmp/ccDQHZn2.o:(.bss+0x0): first defined here /usr/bin/ld: Warning: size of symbol `global' changed from 4 in ao to 1 in bo 

    AFAIR, en C ++, les variables dans différentes unités de traduction ont exactement la même déclaration pour fonctionner.