Namespaces
Variants

Replacing text macros

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Препроцессор поддерживает текстовую макроподстановку. Также поддерживается функциональная текстовая макроподстановка.

Содержание

Синтаксис

#define идентификатор список-замены  (необязательно) (1)
#define идентификатор  ( параметры  ) список-замены  (необязательно) (2)
#define идентификатор  ( параметры  , ...) список-замены  (необязательно) (3) (начиная с C++11)
#define идентификатор  (...) список-замены  (необязательно) (4) (начиная с C++11)
#undef идентификатор (5)

Объяснение

#define директивы

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

Макросы, подобные объектам

Объектоподобные макросы заменяют каждое вхождение определённого identifier на replacement-list . Версия (1) директивы #define работает именно таким образом.

Макросы, подобные функциям

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

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

Для версии (2) количество аргументов должно совпадать с количеством параметров в определении макроса. Для версий (3,4) количество аргументов должно быть не меньше количества параметров ( не (начиная с C++20) учитывая ... ). В противном случае программа является некорректной. Если идентификатор не находится в функциональной нотации, т.е. не имеет скобок после себя, он вообще не заменяется.

Версия (2) директивы #define определяет простой функциональный макрос.

Версия (3) директивы #define определяет функционально-подобный макрос с переменным количеством аргументов. Дополнительные аргументы (называемые переменными аргументами ) могут быть доступны с использованием идентификатора __VA_ARGS__ , который затем заменяется на аргументы, переданные вместе с идентификатором для замены.

Директива #define версии (4) определяет функционально-подобный макрос с переменным количеством аргументов, но без обычных аргументов. Аргументы (называемые переменными аргументами ) могут быть доступны только с помощью идентификатора __VA_ARGS__ , который затем заменяется на аргументы, переданные вместе с идентификатором для замены.

Для версий (3,4), replacement-list может содержать последовательность токенов __VA_OPT__( content  ) , которая заменяется на content если __VA_ARGS__ не пуст, и раскрывается в ничто в противном случае.

#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 };
(since C++20)

Примечание: если аргумент макроса, подобного функции, содержит запятые, не защищённые парными скобками (чаще всего встречается в списках аргументов шаблонов, как в assert ( std:: is_same_v < int , int > ) ; или BOOST_FOREACH ( std:: pair < int , int > p, m ) ), запятая интерпретируется как разделитель аргументов макроса, что приводит к ошибке компиляции из-за несоответствия количества аргументов.

Сканирование и Замена
  • Сканирование отслеживает макросы, которые были заменены. Если сканирование находит текст, соответствующий такому макросу, оно помечает его как «игнорируемый» (все последующие сканирования будут его игнорировать). Это предотвращает рекурсию.
  • Если сканирование обнаруживает функциональный макрос, аргументы сканируются перед помещением в replacement-list . За исключением случаев, когда операторы # и ## принимают аргумент без сканирования.
  • После замены макроса результирующий текст сканируется.

Обратите внимание, что возможно определить псевдорекурсивный макрос:

#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)

В противном случае поведение не определено.

# и ## операторы

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

Когда # появляется перед __VA_ARGS__ , всё раскрытое содержимое __VA_ARGS__ заключается в кавычки:

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")
(since C++11)

Оператор ## между любыми двумя последовательными идентификаторами в replacement-list выполняет замену параметров на два идентификатора (которые сначала не макроподставляются), а затем объединяет результат. Эта операция называется "конкатенацией" или "склейкой токенов". Только токены, которые вместе образуют допустимый токен, могут быть склеены: идентификаторы, образующие более длинный идентификатор, цифры, образующие число, или операторы + и = , образующие += . Комментарий не может быть создан склейкой / и * , поскольку комментарии удаляются из текста до начала макроподстановки. Если результат конкатенации не является допустимым токеном, поведение не определено.

Примечание: некоторые компиляторы предоставляют расширение, позволяющее ## появляться после запятой и перед __VA_ARGS__ , в этом случае ## ничего не делает при наличии переменных аргументов, но удаляет запятую при отсутствии переменных аргументов: это позволяет определять макросы, такие как fprintf ( stderr , format, ##__VA_ARGS__) . Этого также можно достичь стандартным способом с использованием __VA_OPT__ , например fprintf ( stderr , format __VA_OPT__ ( , ) __VA_ARGS__ ) . (since C++20)

#undef директива

Директива #undef отменяет определение идентификатора , то есть аннулирует предыдущее определение идентификатора , заданное директивой #define . Если с идентификатором не связан макрос, данная директива игнорируется.

Предопределенные макросы

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

__cplusplus
обозначает версию стандарта C++, которая используется, раскрывается в значение
  • 199711L (до C++11) ,
  • 201103L (C++11) ,
  • 201402L (C++14) ,
  • 201703L (C++17) ,
  • 202002L (C++20) , или
  • 202302L (C++23)
    (макроконстанта)
__STDC_HOSTED__
(C++11)
раскрывается в целочисленную константу 1 если реализация является hosted (работает под ОС), 0 если freestanding (работает без ОС)
(макроконстанта)
__FILE__
раскрывается в имя текущего файла, как строковый литерал, может быть изменено директивой #line
(макроконстанта)
__LINE__
раскрывается в номер строки текущей физической исходной строки , целочисленная константа, может быть изменено директивой #line
(макроконстанта)
__DATE__
раскрывается в дату трансляции, строковый литерал вида "Mmm dd yyyy" . Первый символ "dd" является пробелом, если день месяца меньше 10. Название месяца такое же, как генерируется std:: asctime ( )
(макроконстанта)
__TIME__
раскрывается во время трансляции, строковый литерал вида "hh:mm:ss"
(макроконстанта)
__STDCPP_DEFAULT_NEW_ALIGNMENT__
(C++17)
раскрывается в std::size_t литерал, значение которого является выравниванием, гарантированным вызовом alignment-unaware operator new (большие выравнивания будут переданы в alignment-aware перегрузку, такую как 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_EMBED_NOT_FOUND__ __STDC_EMBED_FOUND__ __STDC_EMBED_EMPTY__
(C++26)
раскрывается в 0 , 1 и 2 соответственно
(макроконстанта)

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

__STDC__
определяемая реализацией величина, если присутствует, обычно используется для указания соответствия стандарту C
(макроконстанта)
__STDC_VERSION__
(C++11)
определяемая реализацией величина, если присутствует
(макроконстанта)
__STDC_ISO_10646__
(C++11)

раскрывается в целочисленную константу вида yyyymmL , если wchar_t использует Unicode, дата указывает на последнюю поддерживаемую ревизию Unicode

(до C++23)

определяемая реализацией величина, если присутствует

(начиная с C++23)

(макроконстанта)
__STDC_MB_MIGHT_NEQ_WC__
(C++11)
раскрывается в 1 если 'x' == L 'x' может быть ложным для элемента x базового набора символов, например, в системах на базе EBCDIC, которые используют Unicode для wchar_t
(макроконстанта)
__STDCPP_THREADS__
(C++11)
раскрывается в 1 если программа может иметь более одного потока выполнения
(макроконстанта)
__STDCPP_STRICT_POINTER_SAFETY__
(C++11) (удалено в C++23)
раскрывается в 1 если реализация имеет строгую std::pointer_safety
(макроконстанта)

Значения этих макросов (за исключением __FILE__ и __LINE__ ) остаются постоянными на протяжении всей единицы трансляции. Попытки переопределить или отменить определение этих макросов приводят к неопределённому поведению.

Макросы для проверки языковых возможностей

Стандарт определяет набор препроцессорных макросов, соответствующих возможностям языка C++, введённым в C++11 или позднее. Они предназначены для простого и переносимого способа обнаружения наличия указанных возможностей.

См. Тестирование возможностей для подробностей.

(начиная с C++20)


Примечания

Предопределенная переменная __func__ не является предопределенным макросом, но обычно используется вместе с __FILE__ и __LINE__ , например, в assert .

(since C++11)

Пример

#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 << "output: " #a << '\n'
// Использование макроса в определении последующего макроса
#define WORD "Hello "
#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(million); //обратите внимание на отсутствие кавычек
    std::cout << OUTER(World) << '\n';
    std::cout << OUTER(WORD World) << '\n';
}

Вывод:

abcd: 12
fff: 2
qqq: 23
34
output: million
Hello World
Hello WORD World

Отчеты о дефектах

Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение как опубликовано Корректное поведение
CWG 2908 C++98 было неясно, расширяется ли __LINE__ до текущего
номера физической строки или текущего номера логической строки
расширяется до текущего
номера физической строки
LWG 294 C++98 единица трансляции, включающая заголовок стандартной библиотеки, могла содержать
макросы, определяющие имена, объявленные в других заголовках стандартной библиотеки
запрещено
P2621R2 C++23 универсальные символьные имена не разрешались
формировать с помощью конкатенации токенов
разрешено

Смотрите также

C++ documentation для Macro Symbol Index
C documentation для Replacing text macros