- Include guard
-
Эта статья или раздел нуждается в переработке. Пожалуйста, улучшите статью в соответствии с правилами написания статей.- Правильный заголовок этой статьи — #include guard. Он показан некорректно из-за технических ограничений.
В языках программирования Си и C++ директивы #include guards (защита подключения) иногда называется macro guard (макрозащита) — это особая конструкция, применяемая для избежания проблем с «двойным подключением» при использовании директивы компилятора
#include
. Добавление #include guards в заголовочный файл является одним из способов сделать этот файл идемпотентным.Содержание
Двойное подключение
Следующий фрагмент кода на языке Си демонстрирует потенциальные проблемы, которые могут возникнуть, если пропустить #include guards:
- Файл grandfather.h
struct foo { int member; };
- Файл father.h
#include "grandfather.h"
- Файл child.c
#include "grandfather.h" #include "father.h"
Здесь к файлу «child.c» напрямую подключаются две копии заголовочного файла «grandfather.h». Это может вызвать ошибку компиляции, так как структура типа
foo
явным образом определяется дважды.Применение #include guards
- Файл grandfather.h
#ifndef H_GRANDFATHER #define H_GRANDFATHER struct foo { int member; }; #endif
- Файл father.h
#include "grandfather.h"
- Файл child.c
#include "grandfather.h" #include "father.h"
В данном примере первое включение файла «grandfather.h» вызывает макроопределение
H_GRANDFATHER
. Далее, когда к «child.c» подключается «grandfather.h» второй раз, проверка#ifndef
выдаёт ошибку, и препроцессор пропускает#endif
, таким образом избегая второго определенияstruct foo
. В результате программа компилируется корректно.Проблемы использования
Чтобы #include guards работали корректно, каждую директиву необходимо проверить и, соответственно, каждая директива должна корректно пройти тест и набор условий различных инструкций препроцессора. Поэтому, проект с использованием #include guards должен отрабатывать связную схему наименования для подключаемых директив, и должен убеждаться, что схема не противоречит используемым посторонним заголовочным файлам или именам любых глобально видимых инструкций.
По этой причине, во многих случаях (в языках Си и C++) используется нестандартная директива
#pragma once
. Эта директива, указанная в начале заголовочного файла, будет указывать, что файл должен подключаться только один раз. Этот подход, однако, может плохо сказаться в виде потенциальной сложности определения ситуации, когда две директивы#include
, указанные в разных местах, на самом деле ссылаются на один заголовок (например, при помощи символьной ссылки в Unix-подобных системах). Более того, так как#pragma once
не является стандартной директивой, её семантика может серьёзно изменяться в зависимости от применения.См. также
Дополнительные источники
Категории:- Язык программирования Си
- C++
Wikimedia Foundation. 2010.