19 Preprocessing directives [cpp]

19.1 Conditional inclusion [cpp.cond]

defined-macro-expression:
	defined identifier
	defined ( identifier )
h-preprocessing-token:
	any preprocessing-token other than >
h-pp-tokens:
	h-preprocessing-token
	h-pp-tokens h-preprocessing-token

has-include-expression:
	__has_­include ( < h-char-sequence > )
	__has_­include ( " q-char-sequence " )
	__has_­include (   string-literal  )
	__has_­include ( < h-pp-tokens     > )

Выражение, управляющее условным включением, должно быть интегральным постоянным выражением, за исключением того, что идентификаторы (включая те, которые лексически идентичны ключевым словам) интерпретируются, как описано ниже,145 и может содержать ноль или более defined-macro-expressions и / или has-include-expressions как унарные операторные выражения.

A defined-macro-expressionоценивает, определен 1 ли идентификатор в настоящее время как имя макроса (то есть, если он предопределен или был предметом #define директивы предварительной обработки без промежуточной #undef директивы с тем же идентификатором субъекта), 0 если это не так.

Третья и четвертая формы has-include-expression рассматриваются только в том случае, если ни первая, ни вторая формы не совпадают, и в этом случае токены предварительной обработки обрабатываются так же, как и в обычном тексте.

Заголовок или исходный файл, идентифицированный заключенной в скобки последовательностью токенов предварительной обработки в каждом содержащемся has-include-expression , ищется, как если бы эта последовательность токенов предварительной обработки была pp-tokensв #include директиве, за исключением того, что дальнейшее расширение макроса не выполняется. Если такая директива не удовлетворяет синтаксическим требованиям #include директивы, программа плохо сформирована. В has-include-expressionпринимает значение , 1 если поиск исходного файла завершается успешно, и в 0 случае неудачи поиска.

В #ifdef и #ifndef директивах, и defined оператор условного включения, будут рассматривать , __has_­include как если бы это было имя определенного макроса. Идентификатор __has_­include не должен появляться ни в каком контексте, не упомянутом в этом разделе.

Каждый токен предварительной обработки, который остается (в списке токенов предварительной обработки, который станет управляющим выражением) после того, как произошли все замены макросов, должен быть в лексической форме a token.

Директивы предварительной обработки форм

# if		constant-expression new-line groupopt
# elif		constant-expression new-line groupopt

проверьте, является ли выражение управляющей константы ненулевым.

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

После того, как все замены из-за расширения макроса и выполнения оценок defined-macro-expressions и has-include-expressions были выполнены, все оставшиеся идентификаторы и ключевые слова, кроме true и false, заменяются на pp-number 0, а затем каждый токен предварительной обработки преобразуется в токен. [ Note: An alternative token не является идентификатором, даже если его написание полностью состоит из букв и подчеркиваний. Поэтому замене он не подлежит. ]end note

Результирующие токены содержат управляющее постоянное выражение, которое оценивается в соответствии с правилами [expr.const] использования арифметики, которая имеет по крайней мере диапазоны, указанные в [support.limits]. Для целей этого преобразования и оценки токена все целочисленные типы со знаком и без знака действуют так, как если бы они имели то же представление, что и, соответственно, intmax_­t или uintmax_­t ([cstdint]). [ Note: Таким образом, в реализации, где std​::​numeric_­limits<int>​::​max() есть 0x7FFF и std​::​numeric_­limits<unsigned int>​::​max() есть 0xFFFF, целочисленный литерал 0x8000 имеет знаковый и положительный знак внутри #if выражения, даже если он без знака в translation phase 7. ] Это включает интерпретацию символьных литералов, которая может включать преобразование управляющих последовательностей в элементы набора символов выполнения. Соответствует ли числовое значение для этих символьных литералов значению, полученному, когда идентичный символьный литерал встречается в выражении (кроме директивы or ), определяется реализацией. [ Таким образом, не гарантируется , что постоянное выражение в следующей директиве и операторе будет иметь одно и то же значение в этих двух контекстах: end note#if#elifNote: #ifif

#if 'z' - 'a' == 25
if ('z' - 'a' == 25)

end note] Кроме того, вопрос о том, может ли односимвольный символьный литерал иметь отрицательное значение, определяется реализацией.bool Перед продолжением обработки каждое подвыражение с типом подвергается интегральному продвижению.

Директивы предварительной обработки форм

# ifdef		identifier new-line groupopt
# ifndef		identifier new-line groupopt

проверьте, определен ли идентификатор в настоящее время как имя макроса. Их условия эквивалентны и соответственно.#if defined identifier#if !defined identifier

Состояние каждой директивы проверяется по порядку. Если он принимает значение false (ноль), группа, которую он контролирует, пропускается: директивы обрабатываются только через имя, которое определяет директиву, чтобы отслеживать уровень вложенных условных выражений; остальные токены предварительной обработки директив игнорируются, как и другие токены предварительной обработки в группе. Обрабатывается только первая группа, условие управления которой оценивается как истинное (ненулевое); любые последующие группы пропускаются, а их управляющие директивы обрабатываются так, как если бы они были в пропущенной группе. Если ни одно из условий не оценивается как истинное, и есть директива, обрабатывается группа, управляемая объектом; при отсутствии директивы все группы до нее пропускаются.#else #else#else#endif 146

[ Example: Это демонстрирует способ включить средство библиотеки optional , только если оно доступно:

#if __has_include(<optional>)
#  include <optional>
#  define have_optional 1
#elif __has_include(<experimental/optional>)
#  include <experimental/optional>
#  define have_optional 1
#  define experimental_optional 1
#else
#  define have_optional 0
#endif

end example]

Поскольку выражение управляющей константы оценивается на этапе трансляции 4, все идентификаторы либо являются, либо не являются именами макросов - просто отсутствуют ключевые слова, константы перечисления и т. Д.

Как указано в синтаксисе, токен предварительной обработки не должен следовать за директивой#else или #endifперед завершающим символом новой строки. Однако комментарии могут появляться в любом месте исходного файла, в том числе в директиве предварительной обработки.