Замена текстовых макросов
Предпроцессор поддерживает замену текстовых макросов и замену текстовых макросов вида функций.
Синтаксис
#define идентификатор список_замены (необязательно) | (1) | |
#define идентификатор ( параметры ) список_замены | (2) | |
#define идентификатор ( параметры, ... ) список_замены | (3) | (с C99) |
#define идентификатор ( ... ) список_замены | (4) | (с C99) |
#undef идентификатор | (5) |
Объяснение
Директивы #define
Директивы #define определяют идентификатор как макрос, то есть они инструктируют компилятор заменить все последующие вхождения идентификатора на список_замены, который может быть дополнительно обработан. Если идентификатор уже определён как макрос любого типа, программа некорректна, если определения не идентичны.
Макросы типа объектов
Макросы типа объектов заменяют каждое вхождение определённого идентификатора на список_замены. Версия (1) директивы #define ведет себя точно так же.
Макросы типа функций
Макросы типа функций заменяют каждое вхождение определённого идентификатора на список_замены, принимая при этом количество аргументов, которые затем заменяют соответствующие вхождения любых из параметров в список_замены.
Синтаксис вызова макроса типа функции похож на синтаксис вызова функции: каждое вхождение имени макроса, за которым следует ( как следующий предпроцессорный токен, вводит последовательность токенов, которая заменяется списком замены. Последовательность завершается соответствующим ) токеном, пропуская промежуточные парные левые и правые скобки.
Количество аргументов должно быть таким же, как количество аргументов в определении макроса (параметры), иначе программа некорректна. Если идентификатор не в функциональной нотации, т.е. не имеет скобок после себя, он не заменяется.
Версия (2) директивы #define определяет простой макрос типа функции.
Версия (3) директивы #define определяет макрос типа функции с переменным числом аргументов. Дополнительные аргументы можно получить, используя __VA_ARGS__ идентификатор, который затем заменяется на аргументы, предоставленные с идентификатором, подлежащим замене.
Версия (4) директивы #define определяет макрос типа функции с переменным числом аргументов, но без обычных аргументов. Аргументы можно получить только с помощью __VA_ARGS__ идентификатора, который затем заменяется на аргументы, предоставленные с идентификатором, подлежащим замене.
| Для версий (3,4), список_замены может содержать последовательность токенов #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 });), запятая интерпретируется как разделитель аргументов макроса, что приводит к ошибке компиляции из-за несоответствия количества аргументов.
Операторы # и ##
В макросах типа функций оператор # перед идентификатором в списке_замены выполняет замену параметра на идентификатор и заключает результат в кавычки, эффективно создавая строковый литерал. Кроме того, предпроцессор добавляет обратные слэши для экранирования кавычек, окружающих вложенные строковые литералы, если таковые имеются, и удваивает обратные слэши внутри строки по мере необходимости. Все начальные и конечные пробелы удаляются, а любая последовательность пробелов посредине текста (но не внутри вложенных строковых литералов) сводится к одному пробелу. Эта операция называется "строковая замена". Если результат строковой замены не является допустимым строковым литералом, поведение не определено.
| Когда #define showlist(...) puts(#__VA_ARGS__)
showlist(); // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int") | (с C99) |
Оператор ## между любыми двумя последовательными идентификаторами в списке_замены выполняет замену параметров на эти идентификаторы, а затем конкатенирует результат. Эта операция называется "конкатенацией" или "склейкой токенов". Склеиваться могут только токены, образующие вместе допустимый токен: идентификаторы, образующие более длинный идентификатор, цифры, образующие число, или операторы + и = образующие +=. Комментарий не может быть создан путём склеивания / и *, так как комментарии удаляются из текста перед рассмотрением подстановки макросов. Если результат конкатенации не является допустимым токеном, поведение не определено.
Примечание: Некоторые компиляторы предлагают расширение, позволяющее ## появляться после запятой и перед __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, если реализация размещена (работает под ОС), 0, если автономная (работает без ОС) (макроконстанта) |
| __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) | расширяется до 1, если поддерживается IEC 60559 (устаревшая)(с C23) (макроконстанта) |
| __STDC_IEC_559_COMPLEX__
(C99) | расширяется до 1, если поддерживается комплексная арифметика IEC 60559 (устаревшая)(с C23) (макроконстанта) |
| __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, если типы атомных данных и библиотека атомных операций не поддерживаются (макроконстанта) |
| __STDC_NO_COMPLEX__
(C11) | расширяется до 1, если комплексные типы и библиотека комплексных математических функций не поддерживаются (макроконстанта) |
| __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__) остаются постоянными в течение всего блока трансляции. Попытки переопределения или удаления этих макросов ведут к неопределенному поведению.
| Предопределенная переменная | (с 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:2023):
- 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++ для Замены текстовых макросов |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/preprocessor/replace