预编译计算一个可变参数列表的长度

看到这个问题, 第一反应就是用参数列表的api,va_start va_arg va_end遍历一遍计算个和,但仔细想想,对于可变参数这个事,在编译前其实就已经确定了,代码里括号里有多少个参数一目了然.

RAC中Racmetamarcos.h中就有一系列宏来完成这件事,硬是在预处理之后就拿到了可变参数个数:

首先看一下定义

#define metamacro_argcount(...) \ 
    metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 

这个宏由几个工具宏一层层展开,现在模拟一下展开过程:

  1. 假如我们要计算的如下:
int count = metamacro_argcount(a, b, c); 
  1. 于是乎第一层展开后:
int count = metamacro_at(20, a, b, c, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 

3.再看metamacro_at的定义:

#define metamacro_at(N, ...) metamacro_concat(metamacro_at, N)(__VA_ARGS__) 
// 下面是metamacro_concat做的事(简写一层) 
#define metamacro_concat_(A, B) A ## B 
  1. 于是乎第二层展开后:
int count = metamacro_at20(a, b, c, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); 

5.再看metamacro_at20这个宏干的事儿:

#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__) 

6.于是乎第三层展开后,相当于截断了前20个参数,留下剩下几个:

int count = metamacro_head(3, 2, 1); 

7.这个metamacro_head:

#define metamacro_head(...) metamacro_head_(__VA_ARGS__, 0) 
#define metamacro_head_(FIRST, ...) FIRST 

8.后面加个0,然后取参数列表第一个,于是乎:

int count = 3; 

这样带来的好处不止是将计算在预处理时搞定,不拖延到运行时恶心cpu;但更重要的是编译检查。比如某些可变参数的实现要求可以填2个参数,可以填3个参数,其他的都不行,这样,也只有这样的宏的实现,才能在编译前就确定了错误。'

细节很重要。 @Dylan.

原文链接

你可能感兴趣的:(预编译计算一个可变参数列表的长度)