c охранники заголовка игнорируются? - PullRequest
1 голос
/ 06 марта 2020

Почему g cc игнорирует эти средства защиты заголовков в этой простой тестовой программе?

Файл заголовка:

#ifndef MYHEADER_H
#define MYHEADER_H

#warning "header declared"

int some_int=0;

#endif

И два. c файла: main . c:

#include "header.h"

int main ()
{
    return some_int;
}

source. c:

#include "header.h"

int get_int()
{
    return some_int;
}

При компиляции с:

  gcc -o out main.c source.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

Как и ожидалось, предупреждение появляется, когда компилятор впервые включает файл заголовка. Но почему охранники заголовков не останавливают второе включение?

Версия g cc:

gcc version 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2)

Ответы [ 3 ]

6 голосов
/ 06 марта 2020

Заголовок защищает от многократного включения в одну единицу перевода (обычно файл .c и все, что оно включает, прямо или косвенно).

У вас есть две единицы перевода, main.c и source.c и они компилируются независимо (даже если вы используете одну строку командной строки gcc main.c source.c). Вот почему вы получаете сообщение об ошибке от компоновщика, а не от компилятора.

Если вы хотите определить объект, вы должны сделать это в файле .c и объявить это как extern в соответствующем файле .h. Файл .c, определяющий объект, компилируется только один раз, и несколько других файлов .c могут видеть объявление в файле .h.

0 голосов
/ 06 марта 2020

Есть 2 блока компиляции: 1 для main.c и 1 для source.c. Они компилируются отдельно (и полностью независимо) компилятором, в результате чего получаются 2 объектных файла (например, main.o соответственно source.o). Каждый из них выводит предупреждение:

In file included from main.c:1:
header.h:4:2: warning: #warning "header declared" [-Wcpp]
    4 | #warning "header declared"
      |  ^~~~~~~

Эти объектные файлы затем связываются компоновщиком в исполняемый файл out.

Но компоновщик обнаруживает, что оба объектных файла определяют один и тот же символ some_int и, следовательно, не может сгенерировать исполняемый файл, в результате чего:

/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
0 голосов
/ 06 марта 2020

Это не игнорирование их. У вас есть два отдельных модуля компиляции, и каждому требуется header.h. Защита заголовка предназначена для того, чтобы один блок компиляции не включал один и тот же заголовок дважды. Например. Если main.c включено header.h' directly, but also included foo.h which also included header.h , when all the includes are expanded the header guard ensures that header.h`, то содержимое появляется только один раз.

...