Почему мои средства защиты от компиляции не предотвращают включение нескольких определений?
У меня есть заголовочный файл xh, который включен более чем в один *.c исходный файл. В этом заголовочном файле определены некоторые структурные переменные.
Я поместил защиту от множественных включений в начало заголовочного файла как:
#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.
#endif//X_H
При сборке я получаю ошибки компоновщика, связанные с несколькими определениями. Я понимаю проблему.
Разве защита от многократного включения в верхней части файла заголовка, как у меня, не будет предотвращать множественные включения в файл заголовка xh и, таким образом, избегать множественных определений переменных, которые есть в xh?
#pragma
когда-то не работает на этом конкретном компиляторе, так в чем же решение? Кто-то разместил этот ответ на похожий вопрос. Кажется, это не работает для меня. Как работает это решение?
6 ответов
Если компоновщик жалуется, это означает, что у вас есть определения, а не просто объявления в вашем заголовке. Вот пример того, что было бы неправильно.
#ifndef X_H
#define X_H
int myFunc()
{
return 42; // Wrong! definition in header.
}
int myVar; // Wrong! definition in header.
#endif
Вы должны разделить это на исходный файл и файл заголовка следующим образом:
Заголовок:
#ifndef X_H
#define X_H
extern int myFunc();
extern int myVar;
#endif
C Источник:
int myFunc()
{
return 42;
}
int myVar;
Защита заголовка хороша только для одного модуля компиляции, то есть исходного файла. Если вам случится включить заголовочный файл несколько раз, возможно, потому что все заголовки включены из main.c
в свою очередь включают stdio.h
тогда охранники помогут.
Если у вас есть определение функции f
в x.h
который включен main.c
а также util.c
то это как копирование и вставка определения f
в main.c
при создании main.o
и делать то же самое для util.c
создавать util.o
, Тогда компоновщик будет жаловаться, и это происходит, несмотря на ваши охранники заголовка. Наличие нескольких #include "x.h"
заявления в main.c
возможно, конечно, из-за этих охранников.
Использование include guard защищает один блок компиляции от включения заголовка дважды. Например, если заголовок Bh включает в себя Ah, а B.cpp включает в себя Ah и Bh, все из Ah будет объявлено дважды в компиляции B.cpp, если вы не используете include guard.
Ваши включенные охранники предотвращают это, все хорошо до сих пор.
Но вы получаете несколько определений во время компоновки, то есть два модуля компиляции определяют одно и то же, это, вероятно, означает, что вы получили реальное определение в своем заголовке, используете extern для всех переменных, убедитесь, что функции являются либо встроенными, либо определены в файле cpp.
Если функции не велики, вы можете использовать "inline" перед ними, и компоновщик не будет жаловаться.
Использование защиты от множественного включения предотвращает ошибки компилятора, но вы получаете ошибку компоновщика. У вас есть определения данных в заголовочном файле, которые не используют extern
?
Может быть X_H
уже определено где-то еще? Я только столкнулся с этой проблемой, где Xlib определяет X_H
в /usr/include/X11/Xh
Чтобы проверить, вы можете позвонить gcc -dM -E
(если вы используете gcc), например, в сборочной системе, которую я использую, которая работает с CC=gcc CFLAGS="-dM -E" make
, Если выходной файл содержит #define X_H
даже если вы удалите его из вашего файла (используйте Y_H
например), то это уже определено за пределами вашего исходного кода.