Включить охрану в 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);
Другие вопросы по тегам