Включить охрану в C - PullRequest
       19

Включить охрану в C

0 голосов
/ 22 ноября 2018

У меня есть 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 ]

0 голосов
/ 22 ноября 2018

Проблема с этим - круговое включение.Вы фактически включаете свою функцию, прежде чем объявить свою структуру.Допустим, вы включили config.h (при условии, что вы удалили неправильный файл include 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.

РЕДАКТИРОВАТЬ: я должен упомянуть, что циклическое включение не являетсяэто хорошая вещь, и вы обычно можете найти другое решение, которое менее рискованно.

0 голосов
/ 22 ноября 2018

Когда config.h включает debug.h, debug.h попытается включить config.h, но поскольку защитный макрос CONFIG уже будет определен, обратное действие "include" 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 гарантирует, что все указатели на структуры или объединения должны выглядетьих же достаточно, чтобы вы могли начать использовать указатели на эти типы.)

0 голосов
/ 22 ноября 2018

debug.h не нужен другой заголовок.Вы можете точно определить эту функцию с помощью предварительного объявления только Config_t

struct Config_t;
void somePrintingFunction(struct Config_t* conf);
...