2.6 Вычисленные включения
Иногда необходимо выбрать один из нескольких заголовочных файлов для включения в вашу программу. Например, они могут указывать параметры конфигурации, которые будут использоваться на разных операционных системах. Это можно сделать с помощью цепочки условных операторов,
#if SYSTEM_1 # include "system_1.h" #elif SYSTEM_2 # include "system_2.h" #elif SYSTEM_3 … #endif
что быстро становится утомительным. Вместо этого препроцессор предлагает возможность использовать макрос для имени заголовочного файла. Это называется вычисленным включением. Вместо того, чтобы писать имя заголовочного файла в качестве непосредственного аргумента ‘#include’, вы просто помещаете имя макроса вместо него:
#define SYSTEM_H "system_1.h" … #include SYSTEM_H
SYSTEM_H будет расширен, и препроцессор будет искать system_1.h, как если бы ‘#include’ было написано таким образом изначально. SYSTEM_H может быть определено вашим Makefile с опцией -D.
Вы должны быть внимательны при определении макроса. ‘#define’ сохраняет токены, а не текст. Препроцессор не знает, что макрос будет использоваться в качестве аргумента ‘#include’, поэтому он генерирует обычные токены, а не имя заголовочного файла. Это вряд ли вызовет проблемы, если вы используете включения в двойных кавычках, которые достаточно близки к строковым константам. Однако, если вы используете угловые скобки, у вас могут возникнуть проблемы.
Синтаксис вычисленного включения фактически немного более общий, чем указанный выше. Если первый символ, отличный от пробела, после ‘#include’, не ‘"’ или ‘<’, то вся строка расширяется макросом, как это делается с обычным текстом.
Если строка расширяется до единственной строковой константы, содержимое этой строковой константы является файлом, подлежащим включению. CPP не перепроверяет строку на наличие вложенных кавычек, но также не обрабатывает обратные слэши в строке. Следовательно
#define HEADER "a\"b" #include HEADER
ищет файл с именем a\"b. CPP ищет файл в соответствии с правилами для включений в двойных кавычках.
Если строка расширяется до потока токенов, начинающегося с токена ‘<’ и содержащего токен ‘>’, то токены между ‘<’ и первым ‘>’ объединяются для формирования имени файла, подлежащего включению. Любые пробелы между токенами сводятся к одному пробелу; затем любой пробел после начального ‘<’ сохраняется, но конечный пробел перед закрывающей ‘>’ игнорируется. CPP ищет файл в соответствии с правилами для включений в угловых скобках.
В любом случае, если на строке есть какие-либо токены после имени файла, возникает ошибка, и директива не обрабатывается. Ошибкой также является тот случай, когда результат расширения не соответствует ни одному из двух ожидаемых форматов.
Эти правила являются поведением, зависящим от реализации, согласно стандарту C. Чтобы минимизировать риск различной интерпретации вычисленных включений различными компиляторами, рекомендуется использовать только один макрос типа объект, который расширяется до строковой константы. Это также минимизирует путаницу для людей, читающих вашу программу.
Далее: Заголовочные файлы-обертки, Предыдущее: Альтернативы заголовочным файлам-обёрткам #ifndef, Вверх: Заголовочные файлы [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-8.5.0/cpp/Computed-Includes.html