Включить охрану - Include guard
Эта секция может быть слишком техническим для большинства читателей, чтобы понять. Пожалуйста помогите улучшить это к сделать понятным для неспециалистов, не снимая технических деталей. (Сентябрь 2018 г.) (Узнайте, как и когда удалить этот шаблон сообщения) |
в 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]
Смотрите также
Рекомендации
- ^ Стандарт C ++ (ISO / IEC 14882) раздел 17.4.3.1.2 / 1
- ^ Стандарт C (ISO / IEC 9899) раздел 7.1.3 / 1.
- ^ «Цель C: определение классов». developer.apple.com. 2014-09-17. Получено 2018-10-03.