6.21 Макросы с переменным числом аргументов.
В стандарте ISO C 1999 года макрос может быть объявлен так, чтобы принимать переменное число аргументов, подобно функции. Синтаксис определения макроса аналогичен синтаксису функции. Вот пример:
#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)
Здесь ‘…’ — это переменное число аргументов. При вызове такого макроса он представляет собой нуль или более токенов до закрывающей скобки, завершающей вызов, включая любые запятые. Этот набор токенов заменяет идентификатор __VA_ARGS__ в теле макроса повсюду, где он появляется. Дополнительную информацию см. в руководстве по CPP.
GCC давно поддерживает макросы с переменным числом аргументов и использует другой синтаксис, который позволяет присваивать имя переменным аргументам, как и любому другому аргументу. Вот пример:
#define debug(format, args...) fprintf (stderr, format, args)
Это во всех отношениях эквивалентно примеру ISO C выше, но, возможно, более удобочитаемо и информативно.
GNU CPP имеет два дополнительных расширения макросов с переменным числом аргументов и позволяет использовать их с любым из вышеприведенных форм определения макроса.
В стандартном C вам не разрешается опускать переменный аргумент полностью; но вам разрешается передавать пустой аргумент. Например, этот вызов недопустим в ISO C, поскольку после строки нет запятой:
debug ("A message")
GNU CPP позволяет вам полностью опустить переменные аргументы таким образом. В приведенных выше примерах компилятор будет жаловаться, хотя расширение макроса по-прежнему содержит дополнительную запятую после строки формата.
Для решения этой проблемы CPP ведет себя особенно для переменных аргументов, используемых с оператором склейки токенов ‘##’. Если вместо этого вы напишете
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
и если переменные аргументы опущены или пусты, оператор ‘##’ заставляет препроцессор удалить запятую перед ним. Если вы все же предоставите некоторые переменные аргументы в вызове макроса, GNU CPP не будет жаловаться на операцию склейки, а вместо этого поместит переменные аргументы после запятой. Как и любой другой склеенный аргумент макроса, эти аргументы не будут макрорасширены.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gcc/Variadic-Macros.html