Варіативний макрос
Варіати́вний ма́крос — можливість препроцесором Сі за допомогою спеціального макроса оголошувати підтримку різного числа аргументів.
Макрос зі змінним числом аргументів представлено 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
- ↑ Working draft changes for C99 preprocessor synchronization — http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm [Архівовано 31 липня 2020 у Wayback Machine.]