В C и C ++ языков программирования, #include guard, иногда называемый macro guard, header guard или file guard, - это особая конструкция, используемая для избежать проблемы двойного включения при работе с директивой include.
Препроцессор C обрабатывает директивы формы #include
в исходный файл путем нахождения связанного файла
на диске и путем включения («включая») его содержимого в копию исходного файла известная как единица трансляции, заменяющая в процессе директиву include. Файлы, включенные в этом отношении, обычно представляют собой файлы заголовков , которые обычно содержат объявления из функций и классов или структур. Если определенные языковые конструкции C или C ++ определены дважды, результирующая единица перевода недействительна. Защитники #include предотвращают возникновение этой ошибочной конструкции из-за механизма двойного включения.
Добавление защитных элементов #include в файл заголовка - один из способов сделать этот файл идемпотентным. Другая конструкция для борьбы с двойным включением - это #pragma once, которая является нестандартной, но почти повсеместно поддерживается компиляторами C и C ++ .
Следующий код C демонстрирует реальная проблема, которая может возникнуть при отсутствии защиты #include:
struct foo {int member; };
#include "grandparent.h"
#include "grandparent.h" #include "parent.h"
struct foo {int member; }; struct foo {int member; };
Здесь файл «child.c» косвенно включил две копии текста в заголовочный файл «grandparent.h». Это вызывает ошибку компиляции , поскольку тип структуры foo
, таким образом, будет определен дважды. В C ++ это будет называться нарушением правила определения одного.
В этом разделе тот же код используется с добавлением из # включить охранников. Препроцессор C предварительно обрабатывает файлы заголовков, включая и дополнительно обрабатывает их рекурсивно. Это приведет к правильному исходному файлу, как мы увидим.
#ifndef GRANDPARENT_H #define GRANDPARENT_H struct foo {int member; }; #endif / * GRANDPARENT_H * /
#include "grandparent.h"
#include "grandparent.h" #include "родительский. h "
struct foo {int member; };
Здесь для первого включения "grandparent.h" определен макрос GRANDPARENT_H
. Когда "child.c" включает "grandparent.h" во второй раз, поскольку тест #ifndef
возвращает false, препроцессор переходит к #endif
, таким образом избегая второго определение struct foo
. Программа компилируется правильно.
Различные соглашения об именах для макроса защиты могут использоваться разными программистами. Другие распространенные формы приведенного выше примера включают GRANDPARENT_INCLUDED
, CREATORSNAME_YYYYMMDD_HHMMSS
(с заменой соответствующей информации о времени) и имена, сгенерированные из UUID. (Однако имена, начинающиеся с одного подчеркивания и заглавной буквы, или любое имя, содержащее двойное подчеркивание, например _GRANDPARENT__H
и __GRANDPARENT_H
, являются зарезервировано для языковой реализации и не должно использоваться пользователем.)
Конечно, важно избегать дублирования одного и того же имени макроса include-guard в разных файлах заголовков, поскольку включение 1-го предотвратит 2-е от включения, что приведет к потере любых объявлений, встроенных определений или других #includes во втором заголовке.
Для правильной работы #include охранников каждый охранник должен проверить и условно установить другой макрос препроцессора. Следовательно, проект, использующий охранники #include, должен разработать согласованную схему именования для своих защитных элементов включения и убедиться, что его схема не конфликтует со схемами любых сторонних заголовков, которые он использует, или с именами любых глобально видимых макросов.
По этой причине большинство реализаций C и C ++ предоставляют нестандартную директиву #pragma once
. Эта директива, вставленная в верхнюю часть файла заголовка, гарантирует, что файл будет включен только один раз. В языке Objective-C (который является надмножеством C) введена директива #import
, которая работает точно так же, как #include
, за исключением того, что включает каждый файл. только один раз, что устраняет необходимость в #include guards.