Замена текстовых макросов
Препроцессор поддерживает замену текстового макроса. Также поддерживается замена текстового макроса подобного функции.
Синтаксис
#define идентификатор-списка-замены (необязательно)
|
(1) | ||||||||
#define идентификатор( параметры ) список-замены (необязательно)
|
(2) | ||||||||
#define идентификатор( параметры, ... ) список-замены (необязательно)
|
(3) | (начиная с C++11) | |||||||
#define идентификатор( ... ) список-замены (необязательно)
|
(4) | (начиная с C++11) | |||||||
#undef идентификатор
|
(5) | ||||||||
Объяснение
Директивы #define
Директивы #define определяют идентификатор как макрос, который инструктирует компилятор заменить большинство последовательных вхождений идентификатора на список-замены, который будет дополнительно обработан. Исключения возникают из правил сканирования и замены. Если идентификатор уже определён как макрос любого типа, программа некорректна, если определения не идентичны.
Объектно подобный макрос
Макросы, подобные объекту, заменяют каждое вхождение определённого идентификатора на список-замены. Версия (1) директивы #define ведёт себя точно так.
Подобные функции макросы
Функциональные макросы заменяют каждое вхождение определённого идентификатора на список-замены, дополнительно принимая ряд аргументов, которые затем заменяют соответствующие вхождения любого из параметров в списке-замены.
Синтаксис функционально-подобного вызова макроса аналогичен синтаксису вызова функции: каждый экземпляр имени макроса, за которым следует ( в качестве следующего токена предварительной обработки, представляет последовательность токенов, которая заменяется списком-замены. Последовательность завершается совпадающим токеном ), пропуская промежуточные совпадающие пары левой и правой круглых скобок.
Для версии (2) количество аргументов должно быть таким же, как количество параметров в определении макроса. Для версий (3,4) количество аргументов не должно быть меньше количества параметров (не (начиная с C++20) считая ...). В противном случае программа будет некорректной. Если идентификатор не имеет функциональной нотации, т.е. не имеет скобок после себя, он вообще не заменяется.
Версия (2) директивы #define определяет простой макрос, похожий на функцию.
Версия (3) директивы #define определяет макрос, подобный функции, с переменным числом аргументов. К дополнительным аргументам (называемым переменными аргументами) можно получить доступ с помощью идентификатора __VA_ARGS__, который затем заменяется аргументами, снабженными идентификатором, который нужно заменить.
Версия (4) директивы #define определяет макрос, подобный функции, с переменным числом аргументов, но без обычных аргументов. Аргументы (называемые переменными аргументами) могут быть доступны только с идентификатором __VA_ARGS__, который затем заменяется аргументами, снабженными идентификатором, который нужно заменить.
|
Для версий (3,4) список-замен может содержать последовательность токенов #define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
F(a, b, c) // заменяется на f(0, a, b, c)
F() // заменяется на f(0)
#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
G(a, b, c) // заменяется на f(0, a, b, c)
G(a, ) // заменяется на f(0, a)
G(a) // заменяется на f(0, a)
#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
SDEF(foo); // заменяется на S foo;
SDEF(bar, 1, 2); // заменяется на S bar = { 1, 2 };
|
(начиная с C++20) |
Примечание: если аргумент макроса, подобного функции, включает запятые, которые не защищены совпадающими парами левой и правой круглых скобок (чаще всего встречаются в списках аргументов шаблона, как в assert(std::is_same_v<int, int>); или BOOST_FOREACH(std::pair<int,int> p, m)), запятая интерпретируется как разделитель аргументов макроса, вызывая сбой компиляции из-за несоответствия количества аргументов.
Сканирование и Замена
- Сканирование отслеживает макросы, которые были заменены. Если сканирование находит текст, соответствующий такому макросу, оно помечает его как "игнорируемый" (все сканирования будут его игнорировать). Это предотвращает рекурсию.
- Если при сканировании найден макрос, похожий на функцию, аргументы сканируются перед помещением в список-замены. За исключением операторов # и ##, аргумент принимается без сканирования.
- После замены макроса текст результата сканируется.
Обратите внимание, что можно определить псевдорекурсивный макрос:
#define EMPTY
#define SCAN(x) x
#define EXAMPLE_() EXAMPLE
#define EXAMPLE(n) EXAMPLE_ EMPTY()(n-1) (n)
EXAMPLE(5)
SCAN(EXAMPLE(5))
Вывод:
EXAMPLE_ ()(5 -1) (5)
EXAMPLE_ ()(5 -1 -1) (5 -1) (5)
Зарезервированные имена макросов
Единица трансляции, которая включает заголовок стандартной библиотеки, не может #define или #undef имена, объявленные в каком-либо заголовке стандартной библиотеки.
Единице трансляции, которая использует какую-либо часть стандартной библиотеки, не разрешается использовать имена #define или #undef, лексически идентичные:
|
(начиная с C++11) |
В противном случае поведение не определено.
Операторы # и ##
В макросах, подобных функциям, оператор # перед идентификатором в списке-замен запускает идентификатор через замену параметра и заключает результат в кавычки, фактически создавая строковый литерал. Кроме того, препроцессор добавляет обратную косую черту, чтобы избежать кавычек, окружающих встроенные строковые литералы, если они есть, и при необходимости удваивает обратную косую черту внутри строки. Все начальные и конечные пробелы удаляются, а любая последовательность пробелов в середине текста (но не внутри встроенных строковых литералов) сжимается до одного пробела. Эта операция называется "стрингификацией". Если результат преобразования в строку не является допустимым строковым литералом, поведение не определено.
|
Когда #define showlist(...) puts(#__VA_ARGS__)
showlist(); // расширяется до puts("")
showlist(1, "x", int); // расширяется до puts("1, \"x\", int")
|
(начиная с C++11) |
Оператор ## между любыми двумя последовательными идентификаторами в списке-замен запускает замену параметра для двух идентификаторов (которые сначала не раскрываются макросом), а затем объединяет результат. Эта операция называется "конкатенацией" или "вставкой токена". Могут быть вставлены только токены, которые образуют допустимый токен: идентификаторы, образующие более длинный идентификатор, цифры, образующие число, или операторы + и =, которые образуют +=. Комментарий не может быть создан путём вставки / и *, потому что комментарии удаляются из текста до того, как рассматривается подстановка макроса. Если результат конкатенации не является допустимым токеном, поведение не определено.
Примечание: некоторые компиляторы предлагают расширение, которое позволяет ## появляться после запятой и перед __VA_ARGS__, и в этом случае ## ничего не делает, когда переменные аргументы присутствуют, но удаляет запятую, когда переменные аргументы отсутствуют: это позволяет определять макросы, такие как fprintf (stderr, format, ##__VA_ARGS__). Этого также можно добиться стандартным способом, используя __VA_OPT__, например fprintf (stderr, format __VA_OPT__(, ) __VA_ARGS__). (начиная с C++20)
Директива #undef
Директива #undef отменяет определение идентификатора, то есть отменяет предыдущее определение идентификатора директивой #define. Если с идентификатором не связан макрос, директива игнорируется.
Предопределённые макросы
Следующие имена макросов предопределены в каждой единице трансляции.
__cplusplus |
обозначает используемую версию стандарта C++, расширяется до значения
|
__STDC_HOSTED__ (начиная с C++11) |
расширяется до целочисленной константы 1, если реализация гостевая (работает под ОС), 0 если автономная (работает без ОС) (макроконстанта) |
__FILE__ |
расширяется до имени текущего файла, как литерал символьной строки, может быть изменён с помощью директивы #line (макроконстанта) |
__LINE__ |
расширяется до номера строки исходного файла, целочисленной константы, может быть изменён с помощью директивы #line (макроконстанта) |
__DATE__ |
расширяется до даты трансляции, символьный строковый литерал в форме "Ммм дд гггг". Первый символ "дд" пробел, если день месяца меньше 10. Название месяца как будто сгенерировано std::asctime() (макроконстанта) |
__TIME__ |
расширяется до времени трансляции, символьный строковый литерал в форме "чч:мм:сс" (макроконстанта) |
__STDCPP_DEFAULT_NEW_ALIGNMENT__ (начиная с C++17) |
расширяется до литерала std::size_t, значение которого является выравниванием, гарантируемым вызовом неосведомлёного о выравнивании оператора new (более крупные выравнивания будут переданы в перегрузку с учётом выравнивания, например operator new(std::size_t, std::align_val_t) (макроконстанта) |
__STDCPP_BFLOAT16_T____STDCPP_FLOAT16_T____STDCPP_FLOAT32_T____STDCPP_FLOAT64_T____STDCPP_FLOAT128_T__ (C++23) |
расширяется в 1 тогда и только тогда, когда реализация поддерживает соответствующий расширенный тип с плавающей запятой (макроконстанта) |
Следующие дополнительные имена макросов могут быть предопределены реализациями.
__STDC__ |
значение, определяемое реализацией, если присутствует, обычно используется для обозначения соответствия C (макроконстанта) |
__STDC_VERSION__ (начиная с C++11) |
значение, определяемое реализацией, если присутствует (макроконстанта) |
__STDC_ISO_10646__ (начиная с C++11) |
расширяется до целочисленной константы в форме ггггммL, если wchar_t использует Юникод, дата указывает последнюю версию поддерживаемого Юникода (макроконстанта) |
__STDC_MB_MIGHT_NEQ_WC__ (C++11) |
расширяется до 1, если 'x' == L'x' может быть ложным для элемента базового набора символов, например, в системах на основе EBCDIC, которые используют Юникод для wchar_t. (макроконстанта) |
__STDCPP_THREADS__ (начиная с C++11) |
расширяется до 1, если программа может иметь более одного потока выполнения (макроконстанта) |
__STDCPP_STRICT_POINTER_SAFETY__ (начиная с C++11)(удалено в C++23) |
расширяется до 1, если в реализации есть строгие std::pointer_safety (макроконстанта) |
Значения этих макросов (кроме __FILE__ и __LINE__) остаются постоянными во всей единице трансляции. Попытки переопределить или отменить определение этих макросов приводят к неопределённому поведению.
|
Примечание: в области видимости каждого тела функции есть специальная локальная предопределённая переменная с именем |
(начиная с C++11) |
Макросы тестирования особенностей языкаСтандарт определяет набор макросов препроцессора, соответствующих особенностям языка C++, представленным в C++11 или новее. Они предназначены как простой и портируемый способ обнаружения наличия указанных особенностей. Смотрите тестирование функциональности для подробностей. |
(начиная с C++20) |
Пример
#include <iostream>
// Сделайте фабрику функций и используйте ее
#define FUNCTION(name, a) int fun_##name() { return a;}
FUNCTION(abcd, 12)
FUNCTION(fff, 2)
FUNCTION(qqq, 23)
#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) std::cout << "вывод: " #a << '\n'
// Использование макроса в определении более позднего макроса
#define WORD "Привет "
#define OUTER(...) WORD #__VA_ARGS__
int main()
{
std::cout << "abcd: " << fun_abcd() << '\n';
std::cout << "fff: " << fun_fff() << '\n';
std::cout << "qqq: " << fun_qqq() << '\n';
std::cout << FUNCTION << '\n';
OUTPUT(миллион); //обратите внимание на отсутствие кавычек
std::cout << OUTER(Мир) << '\n';
std::cout << OUTER(WORD Мир) << '\n';
}
Вывод:
abcd: 12
fff: 2
qqq: 23
34
вывод: миллион
Привет Мир
Привет WORD Мир
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 294 | C++98 | единица трансляции, включающая заголовок стандартной библиотеки, может содержать макросы, определяющие имена, объявленные в заголовках других стандартных библиотек |
запрещено |
| WG не указан | C++23 | универсальные имена символов не могли образовываться путём конкатенации токенов |
позволено |
Смотрите также
Документация C++ по Указатель Макро Символов
| |
Документация C по Замена текстовых макросов
|