2008-10-30 2 views
32

У меня есть заголовочный файл x.h, который включен более чем одним * .c исходным файлом. Этот заголовочный файл имеет определенные структурные переменные.Почему мои компиляторы не предотвращают множественные включения?

Я поставил несколько предотвращения включения охранника в начале заголовка файла, как:

#ifndef X_H 
#define X_H 
... 
.. 
//header file declarations and definitons. 


#endif//X_H 

На здании я получаю ошибки компоновщика, связанные с несколькими определениями. Я понимаю проблему.

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

  2. #pragma один раз не работает над этим конкретным компилятором, так что же такое решение? Кто-то отправил this ответ на аналогичный вопрос. Кажется, это не работает для меня. Как это решение работает?

+1

@ Stephen: Если вы уже редактируете заголовок вопроса, пожалуйста, также взгляните на тело (и, возможно, на теги, хотя и не здесь). Это позволяет избежать дублирования редактирования (и удара). – 2011-08-23 18:18:36

+0

@Paulo Пропустил это, я пытался следить за ним, хотя, спасибо за напоминание! – Stephen 2011-08-23 18:22:21

ответ

2

Использование множественного караул включения предотвращает компилятора ошибки, но вы получаете сообщение об ошибке компоновщика. У вас есть определения данных в файле заголовка, которые не используют extern?

9

Использование защитных ограждений предотвращает включение одного блока компиляции из заголовка дважды. Например. если заголовок B.h включает в себя A.h и B.cpp включает в себя A.h и B.h, все из A.h будет объявлено дважды в компиляции B.cpp, если вы не использовали include guard.

Ваши охранники включают предотвращение этого, все в порядке до сих пор.

Но вы получаете несколько определений во времени связи, т. Е. Две единицы компиляции определяют одно и то же, это, вероятно, означает, что вы получили реальное определение в своем заголовке, используйте extern для всех переменных, убедитесь, что функции либо встроены, либо определены в файл cpp.

35

Если компоновщик жалуется, это означает, что у вас есть определения, а не просто объявления в заголовке. Вот пример того, что было бы неправильно.

#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; 
+0

«int myVar;» не более чем предварительное определение; это обычно не вызывает проблем. Если бы был инициализатор, это было бы. Тем не менее, я всегда использую явный extern, как вы показываете в «фиксированной» версии. – 2008-10-30 23:13:00

4

Если функции не являются большими, вы можете использовать «inline» перед ними, и компоновщик не будет жаловаться.

7

Защитные ограждения заголовка хороши только для одного блока компиляции, то есть исходного файла. Если вы включаете заголовочный файл несколько раз, возможно, потому что все заголовки, включенные с 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.

0

Возможно, X_H уже определен где-то в другом месте? Я просто столкнулся с этой проблемой, где Xlib определяет X_H в /usr/include/X11/X.h.

Чтобы проверить, вы можете позвонить gcc -dM -E (если вы используете gcc), например. в buildsystem я использую это с CC=gcc CFLAGS="-dM -E" make. Если выходной файл содержит #define X_H, хотя вы удаляете его из своего файла (например, используйте Y_H), то он уже определен вне вашего исходного кода.

Смежные вопросы