Варіативний макрос

Варіати́вний ма́крос — можливість препроцесором Сі за допомогою спеціального макроса оголошувати підтримку різного числа аргументів.

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

Синтаксис оголошення

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

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

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

Підтримка

GNU Compiler Collection, починаючи з версії 3.0, C++ Builder 2006 і Visual Studio 2005 [1] [Архівовано 8 квітня 2008 у Wayback Machine.] підтримують макроси зі змінним числом аргументів при компіляції коду як мовою C, так і мовою 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);

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

У деяких випадках альтернативою варіативним макросам може стати звичайний макровиклик. Наприклад, такий код можна використати для налагодження:

#ifdef TRACING
#define TRACE(_p)	printf _p
#else
#define TRACE(_p)
#endif

Якщо макрос TRACING визначено під час компіляції, виклик макроса TRACE буде еквівалентним виклику функції printf:

TRACE(("Виконується рядок %d\n", __LINE__));

Якщо макрос TRACING не визначено, під час роботи програми повідомлення не друкуватиметься. Зверніть увагу, що параметри виклику цього макроса слід укласти в подвійні дужки.

У деяких інших випадках замість варіативних макросів можна використати функціонал stdargs мов C/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.]

Джерела