Replacing text macros
Препроцессор поддерживает текстовую замену макросов и функциональную текстовую замену макросов.
Содержание |
Синтаксис
#define
идентификатор
список-замены
(опционально)
|
(1) | ||||||||
#define
идентификатор
(
параметры
)
список-замены
|
(2) | ||||||||
#define
идентификатор
(
параметры
, ... )
список-замены
|
(3) | (начиная с C99) | |||||||
#define
идентификатор
( ... )
список-замены
|
(4) | (начиная с C99) | |||||||
#undef
идентификатор
|
(5) | ||||||||
Объяснение
#define директивы
Директива
#define
определяет
идентификатор
как макрос, то есть указывает компилятору заменить все последующие вхождения
идентификатора
на
список-замены
, который может быть дополнительно обработан. Если идентификатор уже определён как макрос любого типа, программа является некорректной, за исключением случаев, когда определения идентичны.
Макросы, подобные объектам
Объектоподобные макросы заменяют каждое вхождение определённого
идентификатора
на
список-замены
. Версия (1) директивы
#define
работает именно таким образом.
Макросы, подобные функциям
Функциональные макросы заменяют каждое вхождение определенного идентификатора на список-замены , дополнительно принимая ряд аргументов, которые затем заменяют соответствующие вхождения любых параметров в списке-замены .
Синтаксис вызова макроса, подобного функции, аналогичен синтаксису вызова функции: каждое вхождение имени макроса, за которым следует ( в качестве следующего токена препроцессора, вводит последовательность токенов, которая заменяется списком замены. Последовательность завершается соответствующим токеном ), с пропуском промежуточных пар соответствующих левых и правых скобок.
Количество аргументов должно совпадать с количеством аргументов в определении макроса ( parameters ), иначе программа является некорректной. Если идентификатор не находится в функциональной нотации, т.е. не имеет скобок после себя, он вообще не заменяется.
Версия (2) директивы
#define
определяет простой функциональный макрос.
Версия (3) директивы
#define
определяет функционально-подобный макрос с переменным количеством аргументов. Дополнительные аргументы могут быть доступны с использованием идентификатора
__VA_ARGS__
, который затем заменяется аргументами, переданными вместе с идентификатором для замены.
Версия (4) директивы
#define
определяет функционально-подобный макрос с переменным количеством аргументов, но без регулярных аргументов. Аргументы могут быть доступны только с помощью идентификатора
__VA_ARGS__
, который затем заменяется аргументами, переданными вместе с идентификатором для замены.
|
Для версий (3,4),
replacement-list
может содержать последовательность токенов
#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) F(a, b, c) // replaced by f(0, a, b, c) F() // replaced by f(0) #define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__) G(a, b, c) // replaced by f(0, a, b, c) G(a, ) // replaced by f(0, a) G(a) // replaced by f(0, a) #define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ }) SDEF(foo); // replaced by S foo; SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 }; |
(начиная с C23) |
Примечание: если аргумент макроса, подобного функции, содержит запятые, не защищённые парными левыми и правыми скобками (например,
macro
(
array
[
x
=
y, x
+
1
]
)
или
atomic_store
(
p,
(
struct
S
)
{
a, b
}
)
;
), запятая интерпретируется как разделитель аргументов макроса, что вызывает ошибку компиляции из-за несоответствия количества аргументов.
# и ## операторы
В макросах, подобных функциям, оператор
#
перед идентификатором в
replacement-list
выполняет замену параметров для этого идентификатора и заключает результат в кавычки, фактически создавая строковый литерал. Кроме того, препроцессор добавляет обратные слеши для экранирования кавычек, окружающих встроенные строковые литералы (если они есть), и удваивает обратные слеши внутри строки по мере необходимости. Все начальные и конечные пробельные символы удаляются, а любая последовательность пробелов в середине текста (но не внутри встроенных строковых литералов) сводится к одному пробелу. Эта операция называется «стрингификацией». Если результат стрингификации не является корректным строковым литералом, поведение не определено.
|
Когда
#define showlist(...) puts(#__VA_ARGS__) showlist(); // expands to puts("") showlist(1, "x", int); // expands to puts("1, \"x\", int") |
(since C99) |
Оператор
##
между любыми двумя последовательными идентификаторами в
replacement-list
выполняет замену параметров на два идентификатора, а затем объединяет результат. Эта операция называется "конкатенацией" или "склеиванием токенов". Только токены, которые вместе образуют допустимый токен, могут быть склеены: идентификаторы, образующие более длинный идентификатор, цифры, образующие число, или операторы
+
и
=
, которые образуют
+=
. Комментарий не может быть создан путем склеивания
/
и
*
, потому что комментарии удаляются из текста до начала подстановки макросов. Если результат конкатенации не является допустимым токеном, поведение не определено.
Примечание: Некоторые компиляторы предоставляют расширение, позволяющее
##
появляться после запятой и перед
__VA_ARGS__
, в этом случае
##
ничего не делает, когда
__VA_ARGS__
не пуст, но удаляет запятую, когда
__VA_ARGS__
пуст: это делает возможным определение макросов, таких как
fprintf
(
stderr
, format,
##__VA_ARGS__)
.
Порядок вычисления
#
и
##
операторов не определён.
#undef директива
Директива
#undef
отменяет определение
идентификатора
, то есть аннулирует предыдущее определение
идентификатора
, заданное директивой
#define
. Если идентификатор не имеет связанного макроса, директива игнорируется.
Предопределенные макросы
Следующие макросы предопределены в любой единице трансляции:
|
__STDC__
|
раскрывается в целочисленную константу
1
. Этот макрос предназначен для обозначения соответствующей реализации
(макроконстанта) |
|
__STDC_VERSION__
(C95)
|
раскрывается в целочисленную константу типа
long
, значение которой увеличивается с каждой версией стандарта C:
|
|
__STDC_HOSTED__
(C99)
|
раскрывается в целочисленную константу
1
если реализация является hosted (работает под ОС),
0
если freestanding (работает без ОС)
(макроконстанта) |
|
__FILE__
|
раскрывается в имя текущего файла в виде строкового литерала, может быть изменено директивой
#line
(макроконстанта) |
|
__LINE__
|
раскрывается в номер строки исходного файла, целочисленная константа, может быть изменена директивой
#line
(макроконстанта) |
|
__DATE__
|
раскрывается в дату трансляции, строковый литерал формата "Mmm dd yyyy". Название месяца такое же, как генерируется функцией
asctime
, и первый символ "dd" является пробелом, если день месяца меньше 10
(макроконстанта) |
|
__TIME__
|
раскрывается во время трансляции, строковый литерал формата "hh:mm:ss", как во времени, генерируемом функцией
asctime
(
)
(макроконстанта) |
|
__STDC_UTF_16__
(C23)
|
раскрывается в
1
для указания, что
char16_t
использует кодировку UTF-16
(макроконстанта) |
|
__STDC_UTF_32__
(C23)
|
раскрывается в
1
для указания, что
char32_t
использует кодировку UTF-32
(макроконстанта) |
|
__STDC_EMBED_NOT_FOUND__
__STDC_EMBED_FOUND__
__STDC_EMBED_EMPTY__
(C23)
|
раскрываются в
0
,
1
и
2
соответственно
(макроконстанта) |
Следующие дополнительные имена макросов могут быть предопределены реализацией:
|
__STDC_ISO_10646__
(C99)
|
раскрывается в целочисленную константу вида
yyyymmL
, если
wchar_t
использует Unicode; дата указывает на последнюю поддерживаемую ревизию Unicode
(макрос-константа) |
|
__STDC_IEC_559__
(C99)
(устарело в C23)
|
раскрывается в
1
если поддерживается IEC 60559
(макрос-константа) |
|
__STDC_IEC_559_COMPLEX__
(C99)
(устарело в C23)
|
раскрывается в
1
если поддерживается арифметика комплексных чисел IEC 60559
(макроконстанта) |
|
__STDC_UTF_16__
(C11)
|
раскрывается в
1
если
char16_t
использует кодировку UTF-16
(макроконстанта) |
|
__STDC_UTF_32__
(C11)
|
раскрывается в
1
если
char32_t
использует кодировку UTF-32
(макрос-константа) |
|
__STDC_MB_MIGHT_NEQ_WC__
(C99)
|
раскрывается в
1
если
'x'
==
L
'x'
может быть ложным для члена базового набора символов, например, в системах на базе EBCDIC, которые используют Unicode для
wchar_t
(макроконстанта) |
|
__STDC_ANALYZABLE__
(C11)
|
раскрывается в
1
если поддерживается
анализируемость
(макрос-константа) |
|
__STDC_LIB_EXT1__
(C11)
|
раскрывается в целочисленную константу
201112L
если поддерживаются
интерфейсы проверки границ
(макрос-константа) |
|
__STDC_NO_ATOMICS__
(C11)
|
раскрывается в
1
если
atomic
типы и
atomic operations library
не поддерживаются
(макроконстанта) |
|
__STDC_NO_COMPLEX__
(C11)
|
раскрывается в
1
если
complex types
и
complex math library
не поддерживаются
(макрос-константа) |
|
__STDC_NO_THREADS__
(C11)
|
раскрывается в
1
если
многопоточность
не поддерживается
(макрос-константа) |
|
__STDC_NO_VLA__
(C11)
|
раскрывается в
1
если
массивы переменной длины
и изменяемые типы
(до C23)
автоматической длительности хранения
(начиная с C23)
не поддерживаются
(макроконстанта) |
|
__STDC_IEC_60559_BFP__
(C23)
|
раскрывается в
202311L
если поддерживается арифметика двоичных чисел с плавающей запятой IEC 60559
(макроконстанта) |
|
__STDC_IEC_60559_DFP__
(C23)
|
раскрывается в
202311L
если поддерживается арифметика десятичных чисел с плавающей запятой IEC 60559
(макроконстанта) |
|
__STDC_IEC_60559_COMPLEX__
(C23)
|
раскрывается в
202311L
если поддерживается комплексная арифметика IEC 60559
(макрос-константа) |
|
__STDC_IEC_60559_TYPES__
(C23)
|
раскрывается в
202311L
если поддерживаются обменные и расширенные типы IEC 60559
(макрос-константа) |
Значения этих макросов (за исключением
__FILE__
и
__LINE__
) остаются постоянными на протяжении всей единицы трансляции. Попытки переопределить или отменить определение этих макросов приводят к неопределённому поведению.
|
Предопределённая переменная
__func__
(см.
определение функции
для подробностей) не является макросом препроцессора, несмотря на то, что иногда используется вместе с
|
(начиная с C99) |
Пример
#include <stdio.h> // make function factory and use it #define FUNCTION(name, a) int fun_##name(int x) { return (a) * x; } FUNCTION(quadruple, 4) FUNCTION(double, 2) #undef FUNCTION #define FUNCTION 34 #define OUTPUT(a) puts( #a ) int main(void) { printf("quadruple(13): %d\n", fun_quadruple(13)); printf("double(21): %d\n", fun_double(21)); printf("%d\n", FUNCTION); OUTPUT(billion); // note the lack of quotes }
Вывод:
quadruple(13): 52 double(21): 42 34 billion
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| DR 321 | C99 |
было неясно, выполняется ли всегда
L
'x'
==
'x'
для базового набора символов |
__STDC_MB_MIGHT_NEQ_WC__ добавлен для этой цели |
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
-
- 6.10.4 Макроподстановка (стр: 187-184)
-
- 6.10.9 Предопределенные имена макросов (стр: 186-188)
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 6.10.3 Замена макросов (стр: 121-126)
-
- 6.10.8 Предопределенные имена макросов (стр: 127-129)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 6.10.3 Замена макросов (стр. 166-173)
-
- 6.10.8 Предопределенные имена макросов (стр. 175-176)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 6.10.3 Замена макросов (стр. 151-158)
-
- 6.10.8 Предопределенные имена макросов (стр. 160-161)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
-
- 3.8.3 Замена макросов
-
- 3.8.8 Предопределенные имена макросов
Смотрите также
|
C++ documentation
для
Replacing text macros
|