Включить охрану в C
У меня есть 2 заголовочных файла, которые должны включать один другой.
config.h:
#ifndef CONFIG
#define CONFIG
#include "debug.h"
typedef struct Config_t {
/* some stuff */
} Config;
#endif
debug.h
#ifndef DEBUG
#define DEBUG
#include "config.h"
void somePrintingFunction(Config* conf);
#endif
Вот ошибка, которую я получаю:
debug.h: ошибка: неизвестное имя типа 'Config'
config.c: предупреждение: неявное объявление функции somePrintingFunction
debug.h: ошибка: неизвестное имя типа 'Config'
Я думаю, что это зацикливание в объявлении заголовка?
Редактировать:
Исправлено объединение обоих файлов, что упрощает проектирование. Если вы хотите по-настоящему исправить, проверьте в комментариях.
3 ответа
Когда config.h
включает в себя debug.h
, debug.h
постараюсь включить config.h
но так как CONFIG
Защитный макрос уже будет определен, обратное действие "включить" из config.h
будет пропущен, и анализ будет продолжен на следующей строке:
void somePrintingFunction(Config* conf);
без Config
тип был определен.
Как указал StoryTeller, вы можете разорвать взаимную зависимость, объявив вперед Config_t
структура:
struct Config_t;
void somePrintingFunction(struct Config_t* conf);
Начиная с C11, вы также можете сделать typedef
поскольку C11 может обрабатывать дублированные определения типов, если они ссылаются на один и тот же тип.
typedef struct Config_t Config;
void somePrintingFunction(Config* conf);
(Прямое объявление агрегатов (структур или объединений) не позволяет вам объявлять объекты этих типов (если только не было предоставлено полное определение), но поскольку C гарантирует, что все указатели на структуры или объединения должны выглядеть одинаково, их достаточно чтобы позволить вам начать использовать указатели на эти типы.)
Проблема с этим заключается в круговом включении. Вы фактически включаете свою функцию, прежде чем объявить свою структуру. Допустим, вы включаете config.h
(при условии, что вы удалили неправильное включение a.h
препроцессор делает это:
#include "debug.h"
typedef struct Config_t {
/* some stuff */
} Config;
и определяет символ CONFIG
так что этот файл не будет включен дважды. Затем он оценивает оставшиеся:
#include "config.h"
void somePrintingFunction(Config* conf);
typedef struct Config_t {
/* some stuff */
} Config;
и определяет символ DEBUG
, С символом CONFIG
определяется это не будет включать config.h
во второй раз, и таким образом это закончено. Теперь обратите внимание, как объявление функции находится перед объявлением структуры. Чтобы решить эту проблему, используйте предварительную декларацию, подобную этой
#include "config.h"
struct Config_t;
void somePrintingFunction(struct Config_t* conf);
Таким образом, компилятор знает, что Config
до того, как вы его используете. Просто имейте в виду, чтобы определить все функции, которые используют предварительно объявленную структуру или класс в c
файл, потому что предварительно объявленный объект еще не определен, но будет в c
файл.
РЕДАКТИРОВАТЬ: я должен отметить, что циркулярное включение не очень хорошая вещь, и вы обычно можете найти другое решение, которое менее рискованно для здоровья.
debug.h
не нужен другой заголовок. Вы можете точно определить эту функцию с помощью предварительного объявления Config_t
в одиночестве
struct Config_t;
void somePrintingFunction(struct Config_t* conf);