#define в C с тремя точками

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))

Это определение для этих двух макросов; далее в коде LOGI и LOGW используются таким образом

LOGI("accelerometer: x=%f y=%f z=%f",
                                event.acceleration.x, event.acceleration.y,
                                event.acceleration.z);

и так

LOGW("Unable to eglMakeCurrent");

Поскольку я стараюсь избегать сложных макросов и #define в целом, я не могу понять, что на самом деле означает этот макрос. Какую роль здесь играют 3 точки? Что этот #define меняет позже в коде?

Очевидно, я знаю, что 3 точки используются для обозначения неопределенного количества аргументов, но я не знаю, как читать эту ситуацию.


person Ken    schedule 15.09.2012    source источник
comment
Это называется вариативным макросом. gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html   -  person chris    schedule 15.09.2012
comment
@chris, значит, это способ быть менее многословным и определенным образом переставить аргументы?   -  person Ken    schedule 15.09.2012
comment
Хм, я бы использовал ##__VA_ARGS__, но я думаю, это нормально, пока вы должны привести аргумент.   -  person nneonneo    schedule 15.09.2012
comment
@Ken: макрос с переменным числом переменных позволяет макросу принимать произвольное количество аргументов (по духу аналогично функции printf). Таким образом, вы можете дать макросу строку формата и аргументы для строки формата. Как вы видите, чаще всего он используется для переноса функций с переменным числом аргументов.   -  person nneonneo    schedule 15.09.2012


Ответы (1)


В стандарте C99 были представлены вариативные макросы, то есть макросы, подобные функциям, которые могут принимать переменное количество аргументов.

Цитируя последний проект стандарта C, раздел 6.10.3:

Если список-идентификаторов в определении макроса не заканчивается многоточием, количество аргументов (включая аргументы, не состоящие из токенов предварительной обработки) в вызове функционального макроса должно равняться количеству параметров в определении макроса. В противном случае аргументов в вызове должно быть больше, чем параметров в определении макроса (исключая ...). Должен существовать a) токен предварительной обработки, который завершает вызов.

Идентификатор __VA_ARGS__ должен встречаться только в списке замены макроса, подобного функции, который использует запись с многоточием в параметрах.

...

Если в списке идентификаторов в определении макроса есть ..., то конечные аргументы, включая любые разделяющие запятые маркеры предварительной обработки, объединяются в один элемент: переменные аргументы. Количество объединенных таким образом аргументов таково, что после слияния количество аргументов будет на один больше, чем количество параметров в определении макроса (исключая ...).

И в следующем подразделе:

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

Таким образом, вы можете вызывать LOGI или LOGW с любым количеством аргументов, и все они будут развернуты в месте, указанном в определении, ссылкой на __VA_ARGS__.

person Keith Thompson    schedule 15.09.2012
comment
Кстати, разрешен ли стандартом ##__VA_ARGS__ (обычно используемый для обработки случая нулевых аргументов, предоставляемых вариативному макросу)? Это вообще необходимо? - person nneonneo; 15.09.2012
comment
Обозначение ##__VA_ARGS__ является расширением GCC. - person Jonathan Leffler; 15.09.2012
comment
Да, это расширение, и его можно заменить другими методами, которые подсчитывают количество аргументов, получаемых макросом. - person Jens Gustedt; 15.09.2012