一则关于C99中variadic macro的使用经验

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");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值