Включить охрану - Include guard

в C и C ++ языки программирования, #include guard, иногда называемый защита от макросов, защита заголовка или же файловая охрана, это особая конструкция, используемая, чтобы избежать проблемы двойное включение имея дело с включить директиву.

В Препроцессор C процессы директивы формы #include <файл> в исходный файл путем обнаружения связанных файл на диск и включая («включая») его содержимое в копию исходного файла, известного как единица перевода, заменяя директиву include в процессе. Файлы, включенные в этом отношении, обычно файлы заголовков, которые обычно содержат декларации из функции и классы или же структуры. Если определенные конструкции языка C или C ++ определены дважды, результирующая единица перевода является недействительным. Защитники #include предотвращают возникновение этой ошибочной конструкции из-за механизма двойного включения.

Добавление защиты #include в файл заголовка - один из способов сделать этот файл идемпотент. Еще одна конструкция для борьбы двойное включение является #pragma once, который является нестандартным, но почти повсеместно поддерживается в C и C ++. компиляторы.

Двойное включение

Пример

Следующий код на C демонстрирует реальную проблему, которая может возникнуть, если отсутствуют охранники #include:

Файл "grandparent.h"

структура фу {    int член;};

Файл "parent.h"

#включают "grandparent.h"

Файл "child.c"

#включают "grandparent.h"#включают "parent.h"

Результат

структура фу {    int член;};структура фу {    int член;};

Здесь файл "child.c" косвенно включил две копии текста в заголовочный файл "grandparent.h". Это вызывает ошибка компиляции, поскольку тип структуры фу таким образом, будет определено дважды. В C ++ это можно было бы назвать нарушением одно правило определения.

Использование #include guards

Пример

В этом разделе используется тот же код с добавлением охранников #include. В Препроцессор C предварительно обрабатывает файлы заголовков, включая их и в дальнейшем обрабатывает рекурсивно. Это приведет к правильному исходному файлу, как мы увидим.

Файл "grandparent.h"

#ifndef GRANDPARENT_H#define GRANDPARENT_Hструктура фу {    int член;};#endif / * GRANDPARENT_H * /

Файл "parent.h"

#включают "grandparent.h"

Файл "child.c"

#включают "grandparent.h"#включают "parent.h"

Результат

структура фу {    int член;};

Здесь первое включение "grandparent.h" содержит макрос GRANDPARENT_H определенный. Когда "child.c" включает "grandparent.h" во второй раз, поскольку #ifndef test возвращает false, препроцессор переходит к #endif, таким образом избегая второго определения struct foo. Программа компилируется правильно.

Обсуждение

Разные соглашения об именах для охранника макрос может использоваться разными программисты. Другие распространенные формы приведенного выше примера включают GRANDPARENT_INCLUDED, CREATORSNAME_YYYYMMDD_HHMMSS (с заменой соответствующей информации о времени), и имена, созданные из UUID. (Тем не мение, имена начиная с одного подчеркивания и Заглавная буква или любое имя, содержащее двойное подчеркивание, например _GRANDPARENT__H и __GRANDPARENT_H, зарезервированы для языковой реализации и не должны использоваться пользователем.[1][2])

Конечно, важно избегать дублирования одного и того же имени макроса include-guard в разных файлах заголовков, поскольку включение 1-го предотвратит включение 2-го, что приведет к потере любых объявлений, встроенных определений или других #includes в 2-й заголовок.

Трудности

Для правильной работы #include охранников каждый охранник должен проверить и условно установить другой макрос препроцессора. Следовательно, проект, использующий охранники #include, должен разработать согласованную схему именования для своих защитных элементов включения и убедиться, что его схема не конфликтует со схемами любых сторонних заголовков, которые он использует, или с именами любых глобально видимых макросов.

По этой причине большинство реализаций C и C ++ предоставляют нестандартный #pragma once директива. Эта директива, вставленная в верхнюю часть файла заголовка, гарантирует, что файл будет включен только один раз. В Цель-C язык (который является надмножеством C) представил #импорт директива, которая работает точно так же, как #включают, за исключением того, что он включает каждый файл только один раз, что устраняет необходимость в #include guard.[3]

Смотрите также

Рекомендации

  1. ^ Стандарт C ++ (ISO / IEC 14882) раздел 17.4.3.1.2 / 1
  2. ^ Стандарт C (ISO / IEC 9899) раздел 7.1.3 / 1.
  3. ^ «Цель C: определение классов». developer.apple.com. 2014-09-17. Получено 2018-10-03.

внешняя ссылка