C99标准提供了变长参数宏的特性,可以在宏中像经典的printf函数一样使用变长的参数,基本的用法是:
#define AN_EXAMPLE_OF_VARIADIC_MACRO(...) \
THE_IMPLEMENTATION_OF_THIS_MACRO(__VA_ARGS__)
其中的...
告诉编译器这里将会有参数个数不定的参数表,而在宏的实现代码中使用__VA_ARGS__
对这个参数个数不定的参数表进行引用。
...
之前可以插入正常的命名参数,例如:
#define AN_EXAMPLE_OF_VARIADIC_MACRO_WITH_SOMEPARAM(para1, para2, ...) \
THE_IMPLEMENTATION_OF_USING_PARA1(para1) \
THE_IMPLEMENTATION_OF_USING_PARA2(para2) \
THE_IMPLEMENTATION_OF_USING_VARIADIC_MACRO(__VA_ARGS__)
但如果__VA_ARGS__
用在参数表中,且前面有逗号,并且在使用宏时未为...
指定任何参数,则在宏展开时将可能造成编译器报错,例如:
#define AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO(para1, ...) \
printf(para1, __VA_ARGS__);
void main(void)
{
AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO("Hello %s","world")// OK
AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO("Hello world")// compile error: argument 2 is invalid
}
错误原因是,main
函数中第二条语句在宏展开后成为:
printf("Hello world", );
因为逗号后面什么都没有,这显然是一个语法错误。为避免这样的错误发生,需要在宏AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO
的实现中对__VA_ARGS__
加上前缀##
,这样当没有为...
指定任何参数时,编译器在展开宏时将把__VA_ARGS__
前面的逗号删除,从而避免了语法错误的发生:
#define AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO(para1, ...) \
printf(para1, ##__VA_ARGS__);
void main(void)
{
AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO("Hello %s","world")// OK
AN_EXAMPLE_OF_ERROR_USAGE_ON_VARIADIC_MACRO("Hello world")// OK,after macro expansion this line is transfered into : printf("Hello world");
}
需要注意的是,如果__VA_ARGS__
在参数表中并没有前置逗号,则不能添加前缀##
,否则编译器会报错。
#define AN_EXAMPLE_OF_ERROR_USAGE_ON_PURE_VARIADIC_MACRO(p ...) \
printf(##__VA_ARGS__);
#define AN_EXAMPLE_OF_CORRECT_USAGE_ON_PURE_VARIADIC_MACRO(p ...) \
printf(__VA_ARGS__);
void main(void)
{
AN_EXAMPLE_OF_ERROR_USAGE_ON_PURE_VARIADIC_MACRO("Hello %s","world")// OK, this line is transfered into : printf("Hello %s","world");
AN_EXAMPLE_OF_ERROR_USAGE_ON_PURE_VARIADIC_MACRO("Hello world")// ERROR,after macro expansion this line is transfered into : printf(##"Hello world");
AN_EXAMPLE_OF_CORRECT_USAGE_ON_PURE_VARIADIC_MACRO("Hello %s","world")// OK, this line is transfered into : printf("Hello %s","world");
AN_EXAMPLE_OF_CORRECT_USAGE_ON_PURE_VARIADIC_MACRO("Hello world")// ERROR,after macro expansion this line is transfered into : printf("Hello world");
}