1
votes

c les protections d'en-tête sont ignorées?

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


2 commentaires

Il n'est inclus qu'une seule fois dans chaque unité de traduction.


Chaque fichier est compilé séparément.


3 Réponses :


6
votes

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>


0 commentaires

0
votes

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.


0 commentaires

0
votes

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"
      |  ^~~~~~~


0 commentaires