19 Preprocessing directives [cpp]

A preprocessing directive состоит из последовательности токенов предварительной обработки, которая удовлетворяет следующим ограничениям: Первый токен в последовательности - это # токен предварительной обработки, который (в начале фазы трансляции 4) является либо первым символом в исходном файле (необязательно после пробела, не содержащего символы новой строки) или следующий за пробелом, содержащий хотя бы один символ новой строки. Последний токен в последовательности - это первый символ новой строки, следующий за первым токеном в последовательности.144 Символ новой строки завершает директиву предварительной обработки, даже если она встречается внутри того, что в противном случае было бы вызовом макроса, подобного функции.

preprocessing-file:
	groupopt
group:
	group-part
	group group-part
group-part:
	control-line
	if-section
	text-line
	# conditionally-supported-directive
control-line:
	# include		pp-tokens new-line
	# define		identifier replacement-list new-line
	# define		identifier lparen identifier-listopt ) replacement-list new-line
	# define		identifier lparen ... ) replacement-list new-line
	# define		identifier lparen identifier-list , ... ) replacement-list new-line
	# undef		identifier new-line
	# line		pp-tokens new-line
	# error		pp-tokensopt new-line
	# pragma		pp-tokensopt new-line
	# new-line
if-section:
	if-group elif-groupsopt else-groupopt endif-line
if-group:
	# if		constant-expression new-line groupopt
	# ifdef		identifier new-line groupopt
	# ifndef		identifier new-line groupopt
elif-groups:
	elif-group
	elif-groups elif-group
elif-group:
	# elif		constant-expression new-line groupopt
else-group:
	# else		new-line groupopt
endif-line:
	# endif		new-line
text-line:
	pp-tokensopt new-line
conditionally-supported-directive:
	pp-tokens new-line
lparen:
	a ( character not immediately preceded by white-space
identifier-list:
	identifier
	identifier-list , identifier
replacement-list:
	pp-tokensopt
pp-tokens:
	preprocessing-token
	pp-tokens preprocessing-token
new-line:
	the new-line character

Текстовая строка не должна начинаться с # токена предварительной обработки. A conditionally-supported-directiveне должен начинаться с каких-либо имен директив, появляющихся в синтаксисе. A conditionally-supported-directiveусловно поддерживается семантикой, определяемой реализацией.

В группе, которая пропущена ([cpp.cond]), синтаксис директивы ослаблен, чтобы позволить любой последовательности токенов предварительной обработки встречаться между именем директивы и следующим символом новой строки.

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

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

Маркеры предварительной обработки в директиве предварительной обработки не подлежат расширению макроса, если не указано иное.

[ Example: В:

#define EMPTY
EMPTY   #   include <file.h>

последовательность токенов предварительной обработки во второй строке является not директивой предварительной обработки, поскольку она не начинается с символа a # в начале фазы трансляции 4, даже если это произойдет после EMPTY замены макроса . ]end example

Таким образом, директивы предварительной обработки обычно называют «линиями». Эти «строки» не имеют другого синтаксического значения, поскольку все пробелы эквивалентны, за исключением определенных ситуаций во время предварительной обработки (см. , Например,# оператор создания литерала символьной строки в [cpp.stringize]).

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перед завершающим символом новой строки. Однако комментарии могут появляться в любом месте исходного файла, в том числе в директиве предварительной обработки.

19.2 Source file inclusion [cpp.include]

#include Директива должна определить заголовок или исходный файл , который может быть обработан реализацией.

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

# include < h-char-sequence > new-line

ищет последовательность выполнения определенных мест для заголовка определен однозначно указанной последовательностью между < и > разделителями, и приводит к замене этой Директивы всего содержимого заголовка. То, как указываются места или идентифицируется заголовок, определяется реализацией.

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

# include " q-char-sequence " new-line

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

# include < h-char-sequence > new-line

с идентичной содержащейся последовательностью (включая > символы, если они есть) из исходной директивы.

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

# include pp-tokens new-line

(что не соответствует ни одной из двух предыдущих форм) разрешено. Маркеры предварительной обработки после include в директиве обрабатываются так же, как и в обычном тексте (т. Е. Каждый идентификатор, определенный в настоящее время как имя макроса, заменяется его списком замены токенов предварительной обработки). Если директива, полученная после всех замен, не соответствует одной из двух предыдущих форм, поведение не определено.147 Метод, с помощью которого последовательность токенов предварительной обработки между a < и > парой токенов предварительной обработки или парой " символов объединяется в один токен предварительной обработки имени заголовка, определяется реализацией.

Реализация должна обеспечивать уникальные отображения для последовательностей, состоящих из одного или нескольких nondigits символов, digits за которыми следует точка (.) и один nondigit. Первый символ не должен быть digit. Реализация может игнорировать различия в алфавитном регистре.

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

[ Note: Хотя реализация может предоставлять механизм для предоставления произвольных исходных файлов доступным для < > поиска, в целом программисты должны использовать < > форму для заголовков, предоставленных с реализацией, и " " форму для источников, находящихся вне контроля реализации. Например:

#include <stdio.h>
#include <unistd.h>
#include "usefullib.h"
#include "myprog.h"

end note]

[ Example: Это иллюстрирует замененные #include макросами директивы:

#if VERSION == 1
    #define INCFILE  "vers1.h"
#elif VERSION == 2
    #define INCFILE  "vers2.h"  // and so on
#else
    #define INCFILE  "versN.h"
#endif
#include INCFILE

end example]

Обратите внимание, что смежные строковые литералы не объединяются в один строковый литерал (см. Этапы перевода в [lex.phases]); таким образом, раскрытие, которое приводит к появлению двух строковых литералов, является недопустимой директивой.

19.3 Macro replacement [cpp.replace]

Два списка замены идентичны тогда и только тогда, когда токены предварительной обработки в обоих имеют одинаковый номер, порядок, орфографию и разделение пробелов, где все разделения пробелов считаются идентичными.

Идентификатор, в настоящее время определенный как объектно-подобный макрос (см. Ниже), может быть переопределен другой #define директивой предварительной обработки при условии, что второе определение является объектным определением макроса и два списка замены идентичны, в противном случае программа имеет неправильный формат. Аналогичным образом, идентификатор, который в настоящее время определяется как макрос, подобный функции (см. Ниже), может быть переопределен другой #define директивой предварительной обработки при условии, что второе определение является определением макроса, подобным функции, которое имеет тот же номер и написание параметров, и два списка замены идентичны, иначе программа будет некорректной.

Между идентификатором и списком замен в определении объектно-подобного макроса должен быть пробел.

Если identifier-listв определении макроса не заканчивается многоточие, количество аргументов (включая те аргументы, которые не содержат токенов предварительной обработки) в вызове макроса, подобного функции, должно равняться количеству параметров в определении макроса. В противном случае в вызове должно быть больше аргументов, чем параметров в определении макроса (исключая ...). Должен существовать ) токен предварительной обработки, который завершает вызов.

Идентификатор __VA_­ARGS__ должен встречаться только в replacement-list функциональном макросе, в параметрах которого используется многоточие.

Идентификатор параметра в макросе, подобном функции, должен быть однозначно объявлен в пределах его области действия.

Идентификатор, следующий сразу за define символом, называется macro name. Для имен макросов существует одно пространство имен. Любые символы пробела, предшествующие или следующие за списком замены токенов предварительной обработки, не считаются частью списка замены ни для одной из форм макроса.

Если # токен предварительной обработки, за которым следует идентификатор, лексически встречается в точке, в которой может начаться директива предварительной обработки, идентификатор не подлежит замене макроса.

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

# define identifier replacement-list new-line

определяет, object-like macro что заставляет каждый последующий экземпляр имени макроса148 заменяться списком замены токенов предварительной обработки, которые составляют оставшуюся часть директивы.149 Затем список замены повторно просматривается для поиска дополнительных имен макросов, как указано ниже.

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

# define identifier lparen identifier-listopt ) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list , ... ) replacement-list new-line

определяет function-like macro с параметрами, использование которых аналогично синтаксически вызову функции. Параметры задаются необязательным списком идентификаторов, область действия которого простирается от их объявления в списке идентификаторов до символа новой строки, который завершает #define директиву предварительной обработки. Каждый последующий экземпляр функционально-подобного имени макроса, за которым следует a ( в качестве следующего токена предварительной обработки, представляет последовательность токенов предварительной обработки, которая заменяется списком замены в определении (вызов макроса). Замененная последовательность токенов предварительной обработки завершается совпадающим ) токеном предварительной обработки, пропуская промежуточные согласованные пары левых и правых скобок предварительной обработки токенов. В последовательности токенов предварительной обработки, составляющих вызов макроса, подобного функции, новая строка считается нормальным символом пробела.

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

Если есть , ... непосредственно предшествующий ) в функции-как макроопределение, то задние аргументах, включая любую разделяющую запятую предварительной обработки маркеры, объединяется для формирования одного товара: variable arguments. Количество аргументов, объединенных таким образом, таково, что после слияния количество аргументов на один больше, чем количество параметров в определении макроса (исключая ...).

Поскольку к моменту замены макроса все символьные литералы и строковые литералы являются токенами предварительной обработки, а не последовательностями, которые могут содержать подпоследовательности, подобные идентификаторам (см. [lex.phases]Этапы трансляции), они никогда не сканируются на предмет имен макросов или параметров.

alternative token Не является идентификатором, даже если его написание полностью состоит из букв и символов подчеркивания. Поэтому невозможно определить макрос, имя которого совпадает с именем альтернативного токена.

A conditionally-supported-directive- это директива предварительной обработки независимо от того, поддерживает ли ее реализация.

19.3.1 Argument substitution [cpp.subst]

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

Идентификатор, __VA_­ARGS__ который встречается в списке замены, должен рассматриваться, как если бы он был параметром, а переменные аргументы должны формировать токены предварительной обработки, используемые для его замены.

19.3.2 The # operator [cpp.stringize]

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

A character string literal - это string-literalбез префикса. Если в списке замены параметру непосредственно предшествует # токен предварительной обработки, оба они заменяются токеном предварительной обработки литерала из односимвольной строки, который содержит написание последовательности токенов предварительной обработки для соответствующего аргумента. Каждое появление пробела между токенами предварительной обработки аргумента становится одним пробелом в литерале строки символов. Пробел перед первым токеном предварительной обработки и после последнего токена предварительной обработки, составляющего аргумент, удаляется. В противном случае, первоначальное написание каждого Preprocessing лексемы аргумента сохраняется в строке литеры, для специальной обработки , за исключением производства написания строк и символьных литералы: а \ символ вставляется перед каждым " и \ характером литеры или строкового литерала (включая" символы- разделители ). Если полученная замена не является допустимым символьным строковым литералом, поведение не определено. Литерал символьной строки, соответствующий пустому аргументу, равен "". Порядок оценки # и ## операторов не определен.

19.3.3 The ## operator [cpp.concat]

## Предварительная обработка маркера не должны происходить в начале или в конце списка замены для любой формы макроопределения.

Если в списке замены макроса, подобного функции, параметру непосредственно предшествует или следует ## токен предварительной обработки, параметр заменяется последовательностью токенов предварительной обработки соответствующего аргумента; однако, если аргумент не содержит токенов предварительной обработки, вместо этого параметр заменяется токеном предварительной обработки метки места размещения.151

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

[ Example: В следующем фрагменте:

#define hash_hash # ## #
#define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y);          // equivalent to char p[] = "x ## y";

Расширение производит на разных этапах:

join(x, y)
in_between(x hash_hash y)
in_between(x ## y)
mkstr(x ## y)
"x ## y"

Другими словами, при раскрытии hash_­hash создается новый токен, состоящий из двух смежных острых знаков, но этот новый токен не является ## оператором. ] end example

Жетоны предварительной обработки меток не отображаются в синтаксисе, поскольку они являются временными объектами, которые существуют только на этапе перевода 4.

19.3.4 Rescanning and further replacement [cpp.rescan]

После того, как все параметры в списке замены были заменены и # и ## обработка имеет место, все placemarker предобработки лексем удаляется. Затем результирующая последовательность токенов предварительной обработки повторно сканируется вместе со всеми последующими токенами предварительной обработки исходного файла для замены других имен макросов.

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

Полученная в результате полностью замененная макросами последовательность токенов предварительной обработки не обрабатывается как директива предварительной обработки, даже если она похожа на нее, но все выражения унарных операторов прагмы в ней затем обрабатываются, как указано [cpp.pragma.op] ниже.

19.3.5 Scope of macro definitions [cpp.scope]

Определение макроса длится (независимо от структуры блока) до тех пор, пока#undef не встретится соответствующая директива или (если не встретится ни одна) до конца единицы трансляции. Макроопределения не имеют значения после фазы перевода 4.

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

# undef identifier new-line

заставляет указанный идентификатор больше не определяться как имя макроса. Он игнорируется, если указанный идентификатор в настоящее время не определен как имя макроса.

[ Example: Самым простым способом использования этой возможности является определение «константы манифеста», как в

#define TABSIZE 100
int table[TABSIZE];

end example]

[ Example: Следующее определяет макрос, подобный функции, значение которого является максимальным из его аргументов. Он имеет преимущества работы с любыми совместимыми типами аргументов и генерации встроенного кода без накладных расходов на вызов функции. У него есть недостатки, заключающиеся в том, что он оценивает один или другой его аргумент второй раз (включая побочные эффекты) и генерирует больше кода, чем функция, если вызывается несколько раз. Он также не может получить свой адрес, поскольку у него его нет.

#define max(a, b) ((a) > (b) ? (a) : (b))

Скобки обеспечивают правильную привязку аргументов и результирующего выражения. ]end example

[ Example: Чтобы проиллюстрировать правила переопределения и пересмотра, последовательность

#define x       3
#define f(a)    f(x * (a))
#undef  x
#define x       2
#define g       f
#define z       z[0]
#define h       g(~
#define m(a)    a(w)
#define w       0,1
#define t(a)    a
#define p()     int
#define q(x)    x
#define r(x,y)  x ## y
#define str(x)  # x

f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
g(x+(3,4)-w) | h 5) & m
    (f)^m(m);
p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
char c[2][6] = { str(hello), str() };

приводит к

f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
int i[] = { 1, 23, 4, 5, };
char c[2][6] = { "hello", "" };

end example]

[ Example: Чтобы проиллюстрировать правила создания символьных строковых литералов и конкатенации токенов, последовательность

#define str(s)      # s
#define xstr(s)     str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
               x ## s, x ## t)
#define INCFILE(n)  vers ## n
#define glue(a, b)  a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW     "hello"
#define LOW         LOW ", world"

debug(1, 2);
fputs(str(strncmp("abc\0d", "abc", '\4')        // this goes away
    == 0) str(: @\n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)

приводит к

printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
#include "vers2.h"      (after macro replacement, before file access)
"hello";
"hello" ", world"

или после конкатенации символьных строковых литералов,

printf("x1= %d, x2= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0: @\n", s);
#include "vers2.h"      (after macro replacement, before file access)
"hello";
"hello, world"

Пространство вокруг # и ## лексемы в определении макроса не является обязательным. ]end example

[ Example: Чтобы проиллюстрировать правила для маркеров предварительной обработки меток, последовательность

#define t(x,y,z) x ## y ## z
int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
  t(10,,), t(,11,), t(,,12), t(,,) };

приводит к

int j[] = { 123, 45, 67, 89,
  10, 11, 12, };

end example]

[ Example: Чтобы продемонстрировать правила переопределения, допустима следующая последовательность.

#define OBJ_LIKE      (1-1)
#define OBJ_LIKE      /* white space */ (1-1) /* other */
#define FUNC_LIKE(a)   ( a )
#define FUNC_LIKE( a )(     /* note the white space */ \
                a /* other stuff on this line
                  */ )

Но следующие переопределения недействительны:

#define OBJ_LIKE    (0)         // different token sequence
#define OBJ_LIKE    (1 - 1)     // different white space
#define FUNC_LIKE(b) ( a )      // different parameter usage
#define FUNC_LIKE(b) ( b )      // different parameter spelling

end example]

[ Example: Наконец, чтобы показать возможности макроса списка переменных аргументов:

#define debug(...) fprintf(stderr, __VA_­ARGS__)
#define showlist(...) puts(#__VA_­ARGS__)
#define report(test, ...) ((test) ? puts(#test) : printf(__VA_­ARGS__))
debug("Flag");
debug("X = %d\n", x);
showlist(The first, second, and third items.);
report(x>y, "x is %d but y is %d", x, y);

приводит к

fprintf(stderr, "Flag");
fprintf(stderr, "X = %d\n", x);
puts("The first, second, and third items.");
((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));

end example]

19.4 Line control [cpp.line]

Строковый литерал #line директивы, если он присутствует, должен быть символьным строковым литералом.

line number Текущей строки источника на единицу больше , чем число новой строки символов для чтения или введенной в translation phase 1 процессе обработки исходного файла для текущего маркера.

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

# line digit-sequence new-line

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

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

# line digit-sequence " s-char-sequenceopt " new-line

аналогично устанавливает предполагаемый номер строки и изменяет предполагаемое имя исходного файла на содержимое литерала символьной строки.

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

# line pp-tokens new-line

(что не соответствует ни одной из двух предыдущих форм) разрешено. Токены предварительной обработки после line директивы обрабатываются так же, как и в обычном тексте (каждый идентификатор, определенный в настоящее время как имя макроса, заменяется своим списком замены токенов предварительной обработки). Если директива, полученная после всех замен, не соответствует одной из двух предыдущих форм, поведение не определено; в противном случае результат обрабатывается соответствующим образом.

19.5 Error directive [cpp.error]

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

# error pp-tokensopt new-line

заставляет реализацию генерировать диагностическое сообщение, которое включает указанную последовательность токенов предварительной обработки, и делает программу некорректной.

19.6 Pragma directive [cpp.pragma]

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

# pragma pp-tokensopt new-line

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

19.7 Null directive [cpp.null]

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

# new-line

не имеет никакого эффекта.

19.8 Predefined macro names [cpp.predefined]

Следующие имена макросов должны быть определены реализацией:

  • __cplusplus
    Целочисленный литерал 201703L.152

  • __DATE__
    Дата перевода исходного файла: символьный строковый литерал формы "Mmm dd yyyy", где названия месяцев совпадают с названиями месяцев, сгенерированными asctime функцией, а первый символ dd - это пробел, если значение меньше 10. Если дата перевода недоступна, должна быть указана действительная дата, определяемая реализацией.

  • __FILE__
    Предполагаемое имя текущего исходного файла (литерал символьной строки).153

  • __LINE__
    Предполагаемый номер строки (в текущем исходном файле) текущей исходной строки (целочисленный литерал).154

  • __STDC_­HOSTED__
    Целочисленный литерал, 1 если реализация является размещенной реализацией, или целочисленный литерал, 0 если это не так.

  • __STDCPP_­DEFAULT_­NEW_­ALIGNMENT__
    Целочисленный литерал типа std​::​size_­t , значение которого является выравниванием, гарантированным вызовом operator new(std​::​size_­t) или operator new[](std​::​size_­t). [ Note: Большие выравнивания будут переданы и operator new(std​::​size_­t, std​::​align_­val_­t)т. Д. ([expr.new]). ]end note

  • __TIME__
    Время перевода исходного файла: символьный строковый литерал формы, "hh:mm:ss" как во времени, сгенерированном asctime функцией. Если время трансляции недоступно, должно быть указано действительное время, определяемое реализацией.

Следующие имена макросов условно определены реализацией:

  • __STDC__
    Предопределено ли __STDC__ оно заранее, и если да, то каково его значение, определяется реализацией.

  • __STDC_­MB_­MIGHT_­NEQ_­WC__
    Целочисленный литерал 1, предназначенный для обозначения того, что в кодировке для wchar_­tчлен базового набора символов не обязательно должен иметь кодовое значение, равное его значению, при использовании в качестве одиночного символа в обычном символьном литерале.

  • __STDC_­VERSION__
    Предопределено ли __STDC_­VERSION__ оно заранее, и если да, то каково его значение, определяется реализацией.

  • __STDC_­ISO_­10646__
    Целочисленный литерал формы yyyymmL (например, 199712L). Если этот символ определен, то каждый символ в требуемом наборе Unicode, когда он хранится в объекте типа wchar_­t, имеет то же значение, что и короткий идентификатор этого символа. Он Unicode required set состоит из всех символов, определенных в ISO / IEC 10646, вместе со всеми поправками и техническими исправлениями по состоянию на указанный год и месяц.

  • __STDCPP_­STRICT_­POINTER_­SAFETY__
    Определен и имеет значение целочисленного литерала 1 тогда и только тогда, когда реализация имеет strict pointer safety.

  • __STDCPP_­THREADS__
    Определен и имеет значение целочисленного литерала 1 тогда и только тогда, когда программа может иметь более одного thread of execution.

Значения предопределенных макросов (кроме __FILE__ и __LINE__) остаются постоянными во всей единице перевода.

Если какое-либо из предварительно определенных имен макросов в этом подпункте или идентификатор definedявляется предметом директивы#define или #undefдирективы предварительной обработки, поведение не определено. Любые другие предопределенные имена макросов должны начинаться с символа подчеркивания в начале, за которым следует заглавная буква или второй знак подчеркивания.

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

Предполагаемое имя исходного файла можно изменить с помощью #line директивы.

Предполагаемый номер строки может быть изменен #line директивой.

19.9 Pragma operator [cpp.pragma.op]

Унарное операторное выражение формы:

_Pragma ( string-literal )

обрабатывается следующим образом: строковый литерал - destringized это удаление L префикса, если он присутствует, удаления ведущих и завершающих двойных кавычек, замены каждой escape-последовательности \" на двойные кавычки и замены каждой escape-последовательности \\ одиночной обратной косой чертой. Результирующая последовательность символов обрабатывается на этапе преобразования 3 для создания токенов предварительной обработки, которые выполняются, как если бы они были pp-tokensв директиве pragma. Исходные четыре токена предварительной обработки в выражении унарного оператора удаляются.

[Example:

#pragma listing on "..\listing.dir"

также может быть выражено как:

_Pragma ( "listing on \"..\\listing.dir\"" )

Последняя форма обрабатывается одинаково, независимо от того, выглядит ли она буквально, как показано, или является результатом замены макроса, как в:

#define LISTING(x) PRAGMA(listing on #x)
#define PRAGMA(x) _Pragma(#x)

LISTING( ..\listing.dir )

end example]