Меню

Главная
Случайная статья
Настройки
Вариативный макрос
Материал из https://ru.wikipedia.org

Вариативный макрос — возможность препроцессором Си при помощи специального макроса объявлять поддержку различного числа аргументов.

Макрос с переменным числом аргументов был представлен в ревизии ISO/IEC 9899:1999 (C99) стандарта языка программирования Си в 1999. Также такие макросы были введены в ISO/IEC 14882:2011 (C++11) стандарта языка программирования C++ в 2011 году[1].

Содержание

Синтаксис объявления

Синтаксис объявления схож с синтаксисом вариативной функции: пропуск «...» используется для обозначения того, что нуль или более аргументов могут быть переданы. При расширении макросом каждый вызов специального идентификатора __VA_ARGS__ в списке замещения макроса заменяется переданными аргументами.

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

В gcc в списке формальных параметров макроса могут быть как обозначенные аргументы (specified arguments), так и переданные вариативно (см. пример).

Поддержка

GNU Compiler Collection, начиная с версии 3.0, C++ Builder 2006 и Visual Studio 2005 [1] поддерживают макросы с переменным числом аргументов при компиляции кода как на языке Си, так и на языке C++. Кроме того, GCC поддерживает вариативные макросы при компиляции кода на языке Objective-C.

Пример

Если требуется printf-подобная функция dprintf(), принимающая имя файла и номер строки, из которой вызывается в качестве аргумента, можно использовать следующий макрос:
void realdprintf (char const *file, int line, char const *fmt, ...); 
#define dprintf(...) realdprintf(__FILE__, __LINE__, __VA_ARGS__)


dprintf() может быть вызвана как:
dprintf("Hello, world");


который дополняется до:
realdprintf(__FILE__, __LINE__, "Hello, world");


или:
dprintf("%d + %d =%d", 2, 2, 5);


который дополняется до:
 
realdprintf(__FILE__, __LINE__, "%d + %d =%d", 2, 2, 5);


Пример неполный не отражает возможности, добавлю:
#define  CALL( _obj, _mtd, _specifiedArg1,_specifiedArg2, ... )  _obj->_mtd(_specifiedArg2,_specifiedArg1, __VA_ARGS__) 


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

Альтернативы

В некоторых случаях альтернативой вариативным макросам может служить обычный макровызов. Например, следующий код можно использовать для отладки:
#ifdef TRACING
#define TRACE(_p)	printf _p
#else
#define TRACE(_p)
#endif


Если макрос TRACING определен во время компиляции, вызов макроса TRACE будет эквивалентен вызову функции printf:
TRACE(("Выполняется строка %d\n", __LINE__));


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

В некоторых других случаях вместо вариативных макросов можно использовать функционал stdargs языков Си/C++ и вызов функции vprintf.

Другой пример:
#if defined ( DEBUG_MCU )
  #define TRACE( args ... )    printf( args )
#else
  #define TRACE( args ... )
#endif


См. также

Примечания
  1. Working draft changes for C99 preprocessor synchronization - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm Архивная копия от 31 июля 2020 на Wayback Machine


Источники
Downgrade Counter