Подтвердить что ты не робот

Почему мои компиляторы не предотвращают включение нескольких определений?

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

В начале файла заголовка я поставил несколько предупреждений о предотвращении включения:

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


#endif//X_H

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Твои охранники предотвращают это, все хорошо до сих пор.

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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