Jump to content

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

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

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

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

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

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

[ редактировать ]

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

Файл "grandparent.h"

[ редактировать ]
struct foo {
    int member;
};

Файл «parent.h»

[ редактировать ]
#include "grandparent.h"

Файл "child.c"

[ редактировать ]
#include "grandparent.h"
#include "parent.h"

Результат

[ редактировать ]
struct foo {
    int member;
};
struct foo {
    int member;
};

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

Использование охранников #include

[ редактировать ]

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

Файл "grandparent.h"

[ редактировать ]
#ifndef GRANDPARENT_H
#define GRANDPARENT_H

struct foo {
    int member;
};

#endif /* GRANDPARENT_H */

Файл «parent.h»

[ редактировать ]
#include "grandparent.h"

Файл "child.c"

[ редактировать ]
#include "grandparent.h"
#include "parent.h"

Результат

[ редактировать ]
struct foo {
    int member;
};

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

Обсуждение

[ редактировать ]

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

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

Трудности

[ редактировать ]

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

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

Другие языки

[ редактировать ]

Некоторые языки поддерживают указание того, что код должен быть включен только один раз, во включающий файл, а не во включаемый файл (как в C/C++, включают защитные элементы и #pragma once):

  • PL/I использует %INCLUDE утверждение как эквивалент C #include директива. IBM Enterprise PL/I также поддерживает %XINCLUDE оператор, который «включит внешний текст в исходную программу, если он ранее не был включен». (Он также предлагает XPROCEDURE заявление, похожее на PROCEDURE оператор, который будет игнорировать второе и последующие появления XPROCEDURE с тем же именем.) [4]
  • Objective- C #import директива (см. выше)
  • PHP include_once[5]

См. также

[ редактировать ]
  1. ^ Стандарт C++ (ISO/IEC 14882), раздел 17.4.3.1.2/1
  2. ^ Стандарт C (ISO/IEC 9899), раздел 7.1.3/1.
  3. ^ «Цель C: Определение классов» . разработчик.apple.com . 17 сентября 2014 г. Проверено 3 октября 2018 г.
  4. ^ Корпорация IBM (август 2017 г.). Enterprise PL/I для z/OS PL/I для AIX Enterprise PL/I для z/OS Справочник по языку, версия 5, выпуск 1 (PDF) . п. 257 . Проверено 7 апреля 2022 г.
  5. ^ «include_once (Справочник по языку PHP)» .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: ef03052740f230a74469ae4624a847d8__1716256320
URL1:https://arc.ask3.ru/arc/aa/ef/d8/ef03052740f230a74469ae4624a847d8.html
Заголовок, (Title) документа по адресу, URL1:
include guard - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)