美文网首页Swift-Li
预编译计算一个可变参数列表的长度

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

作者: Stark_Dylan | 来源:发表于2015-07-03 20:44 被阅读597次

    看到这个问题, 第一反应就是用参数列表的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.

    原文链接

    相关文章

      网友评论

      本文标题:预编译计算一个可变参数列表的长度

      本文链接:https://www.haomeiwen.com/subject/tbryqttx.html