Сравнивайте с английским: нажмите на абзац — оригинал откроется в окне. Кнопка EN под абзацем показывает его прямо в тексте.
Содержание
Введение
Конструирование в C и C++
Construct in C and C++
В языках программирования C и C++ защита #include, иногда называемая защитой макроса, защитой заголовочного файла или защитой файла, представляет собой определенную конструкцию, используемую для предотвращения проблемы двойного включения при работе с директивой #include. Препроцессор C обрабатывает директивы вида #include <file> в исходном файле, находя соответствующий файл на диске и транслируя ("включая") его содержимое в копию исходного файла, известную как единица трансляции, заменяя при этом директиву #include. Файлы, включаемые таким образом, обычно являются заголовочными файлами, которые, как правило, содержат объявления функций и классов или структур. Если директива #include для данного файла встречается несколько раз во время компиляции (например, потому что она присутствует в нескольких других заголовочных файлах), файл обрабатывается снова каждый раз. Однако, если определенные конструкции языка C или C++ определены дважды, полученная единица трансляции становится недействительной. Защиты #include предотвращают возникновение этой ошибочной ситуации, определяя макрос препроцессора при первом включении заголовочного файла и обнаруживая его наличие, чтобы пропускать содержимое файла при последующих включениях. Добавление защиты #include в заголовочный файл – один из способов сделать этот файл идемпотентным. Другой способ борьбы с двойным включением – использование директивы #pragma once, которая не является стандартной, но почти повсеместно поддерживается компиляторами C и C++.
In the C and C++ programming languages, an #include guard, sometimes called a macro guard, header guard or file guard, is a particular construct used to avoid the problem of double inclusion when dealing with the include directive. The C preprocessor processes directives of the form #include <file> in a source file by locating the associated file on disk and transcluding ("including") its contents into a copy of the source file known as the translation unit, replacing the include directive in the process. The files included in this regard are generally header files, which typically contain declarations of functions and classes or structs. If an #include directive for a given file appears multiple times during compilation (i. e. because it appeared in multiple other headers), the file is processed again each time. However, if certain C or C++ language constructs are defined twice, the resulting translation unit is invalid. #include guards prevent this erroneous construct from arising by defining a preprocessor macro when a header is first included, and detecting its presence to skip the file's contents on subsequent inclusions. The addition of #include guards to a header file is one way to make that file idempotent. Another construct to combat double inclusion is #pragma once, which is non standard but nearly universally supported among C and C++ compilers.
Файл "parent.h"
#include "grandparent.h"
#include "grandparent. h"
Файл "child.c"
#include "grandparent.h"
#include "parent.h"
#include "grandparent. h"
#include "parent. h"
Пример
В этом разделе используется тот же код, но с добавлением защиты от многократного включения (#include guards). Препроцессор C обрабатывает файлы заголовков, включая их и рекурсивно применяя к ним предварительную обработку. В результате получится корректный исходный файл, что мы и увидим.
In this section, the same code is used with the addition of #include guards. The C preprocessor preprocesses the header files, including and further preprocessing them recursively. This will result in a correct source file, as we will see.
Файл "parent.h"
#include "grandparent.h"
#include "grandparent. h"
Файл "child.c"
#include "grandparent.h"
#include "parent.h"
#include "grandparent. h"
#include "parent. h"
Обсуждение
Различные соглашения об именовании для макроса-защиты от многократного включения могут использоваться разными программистами. Другие распространенные формы приведенного выше примера включают GRANDPARENT INCLUDED, CREATORSNAME YYYYMMDD HHMMSS (с соответствующей информацией о времени) и имена, сгенерированные из UUID. (Однако имена, начинающиеся с одного подчеркивания и заглавной буквы (в C и C++) или содержащие двойное подчеркивание (только в C++), такие как GRANDPARENT_H и GRANDPARENT__H, зарезервированы для реализации языка и не должны использоваться пользователями.) Разумеется, важно избегать дублирования одного и того же имени макроса защиты от многократного включения в разных файлах заголовков, так как включение первого файла предотвратит включение второго, что приведет к потере всех объявлений, встроенных определений или других директив #include во втором файле заголовка.
Different naming conventions for the guard macro may be used by different programmers. Other common forms of the above example include GRANDPARENT INCLUDED, CREATORSNAME YYYYMMDD HHMMSS (with the appropriate time information substituted), and names generated from a UUID. (However, names starting with one underscore and a capital letter (C and C++) or any name containing double underscore (C++ only), such as GRANDPARENT H and GRANDPARENT H, are reserved to the language implementation and should not be used by the user.) Of course, it is important to avoid duplicating the same include guard macro name in different header files, as including the 1st will prevent the 2nd from being included, leading to the loss of any declarations, inline definitions, or other #includes in the 2nd header.
Трудности
Для корректной работы защиты #include, каждая защита должна проверять и условно устанавливать различный макрос препроцессора. Следовательно, проект, использующий защиту #include, должен разработать последовательную схему именования для своих защит и убедиться, что эта схема не конфликтует со схемами именования заголовков сторонних библиотек или с именами глобально видимых макросов. По этой причине большинство реализаций C и C++ предоставляют нестандартную директиву #pragma once. Эта директива, помещенная в начало файла заголовка, гарантирует, что файл будет включен только один раз. Язык Objective-C (являющийся расширением языка C) представил директиву #import, которая работает аналогично #include, но включает каждый файл только один раз, что устраняет необходимость в защите #include.
For #include guards to work properly, each guard must test and conditionally set a different preprocessor macro. Therefore, a project using #include guards must work out a coherent naming scheme for its include guards, and make sure its scheme doesn't conflict with that of any third party headers it uses, or with the names of any globally visible macros. For this reason, most C and C++ implementations provide a non standard #pragma once directive. This directive, inserted at the top of a header file, will ensure that the file is included only once. The Objective C language (which is a superset of C) introduced an #import directive, which works exactly like #include, except that it includes each file only once, thus obviating the need for #include guards.