Pourquoi gcc ignore-t-il ces protections d'en-tête dans ce programme de test simple?
Le fichier d'en-tête est:
gcc version 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2)
Et les deux fichiers .c sont: main.c:
In file included from main.c:1: header.h:4:2: warning: #warning "header declared" [-Wcpp] 4 | #warning "header declared" | ^~~~~~~ In file included from source.c:1: header.h:4:2: warning: #warning "header declared" [-Wcpp] 4 | #warning "header declared" | ^~~~~~~ /usr/bin/ld: /tmp/ccmAbN1J.o:(.bss+0x0): multiple definition of `some_int'; /tmp/ccEd5PwN.o:(.bss+0x0): first defined here collect2: error: ld returned 1 exit status
source.c:
gcc -o out main.c source.c
Lors de la compilation avec:
#include "header.h" int get_int() { return some_int; }
J'obtiens la sortie suivante:
#include "header.h" int main () { return some_int; }
Comme prévu, l'avertissement apparaît lorsque le compilateur inclut le fichier d'en-tête pour la première fois. Mais pourquoi les gardes d'en-tête n'arrêteront-ils pas la deuxième inclusion?
La version gcc est:
#ifndef MYHEADER_H #define MYHEADER_H #warning "header declared" int some_int=0; #endif
3 Réponses :
Les protections d'en-tête empêchent l'inclusion multiple dans une seule unité de traduction (généralement un fichier .c
et tout ce qu'il comprend, directement ou indirectement).
Vous disposez de deux unités de traduction, main.c
et source.c
, et elles sont compilées indépendamment (même si vous utilisez une seule ligne de commande gcc main.c source.c
). C'est pourquoi vous recevez un message d'erreur de l'éditeur de liens, pas du compilateur.
Si vous souhaitez définir un objet, vous devez le faire dans un fichier .c
et le déclarer comme extern
dans le fichier < code> .h fichier. Le fichier .c
définissant l'objet est compilé une seule fois, et plusieurs autres fichiers .c
peuvent voir la déclaration dans le fichier .h
. < / p>
Il ne les ignore pas. Vous avez là deux unités de compilation distinctes et chacune a besoin de header.h
. Les protections d'en-tête sont destinées à empêcher une seule unité de compilation d'inclure deux fois le même en-tête. Par exemple. Si main.c
incluait directement header.h ', mais incluait également
foo.h qui incluait également
header.h , quand tout les inclusions sont développées la garde d'en-tête garantit que le contenu de
header.h` n'apparaît qu'une seule fois.
Il existe 2 unités de compilation: 1 pour main.c
et 1 pour source.c
. Celles-ci sont compilées séparément (et de manière totalement indépendante) par le compilateur, ce qui donne 2 fichiers objets (par exemple main.o
resp. source.o
). Chacun de ceux-ci imprime l'avertissement:
/usr/bin/ld: /tmp/ccmAbN1J.o:(.bss+0x0): multiple definition of `some_int'; /tmp/ccEd5PwN.o:(.bss+0x0): first defined here collect2: error: ld returned 1 exit status
Ces fichiers objets sont ensuite liés dans un exécutable out
par l'éditeur de liens.
Mais l'éditeur de liens découvre que les deux fichiers objets définissent le même symbole some_int
, et ne parviennent donc pas à générer l'exécutable, ce qui entraîne:
In file included from main.c:1: header.h:4:2: warning: #warning "header declared" [-Wcpp] 4 | #warning "header declared" | ^~~~~~~
Il n'est inclus qu'une seule fois dans chaque unité de traduction.
Chaque fichier est compilé séparément.