• Macro to count number of arguments


    #define PP_ARG_N( \
              _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10, \
             _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
             _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
             _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
             _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
             _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
             _61, _62, _63, N, ...) N
    
    #define PP_RSEQ_N()                                        \
             63, 62, 61, 60,                                   \
             59, 58, 57, 56, 55, 54, 53, 52, 51, 50,           \
             49, 48, 47, 46, 45, 44, 43, 42, 41, 40,           \
             39, 38, 37, 36, 35, 34, 33, 32, 31, 30,           \
             29, 28, 27, 26, 25, 24, 23, 22, 21, 20,           \
             19, 18, 17, 16, 15, 14, 13, 12, 11, 10,           \
              9,  8,  7,  6,  5,  4,  3,  2,  1,  0
    
    #define PP_NARG_(...)    PP_ARG_N(__VA_ARGS__)    
    
    #define PP_NARG(...)     PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
    #define PP_COMMASEQ_N()                                    \
              1,  1,  1,  1,                                   \
              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,           \
              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,           \
              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,           \
              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,           \
              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,           \
              1,  1,  1,  1,  1,  1,  1,  1,  0,  0
    
    #define PP_COMMA()    ,
    
    #define PP_HASCOMMA(...)                                   \
              PP_NARG_(__VA_ARGS__, PP_COMMASEQ_N())
    
    #define PP_NARG(...)                                       \
              PP_NARG_HELPER1(                                 \
                  PP_HASCOMMA(__VA_ARGS__),                    \
                  PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()),        \
                  PP_NARG_(__VA_ARGS__, PP_RSEQ_N()))
    
    #define PP_NARG_HELPER1(a, b, N)    PP_NARG_HELPER2(a, b, N)
    #define PP_NARG_HELPER2(a, b, N)    PP_NARG_HELPER3_ ## a ## b(N)
    #define PP_NARG_HELPER3_01(N)    0
    #define PP_NARG_HELPER3_00(N)    1
    #define PP_NARG_HELPER3_11(N)    N
    
    
    PP_NARG()       // expands to 0
    PP_NARG(x)      // expands to 1
    PP_NARG(x, 2)   // expands to 2

    Explanation:

    The trick in these macros is that PP_HASCOMMA(...) 
    expands to 0 when called with zero or one argument
    and to 1 when called with at least two arguments.
    To distinguish between these two cases,
    I used PP_COMMA __VA_ARGS__ (), which returns a comma
    when __VA_ARGS__ is empty and
    returns nothing when __VA_ARGS__is non-empty.

    Now there are three possible cases:

    1. __VA_ARGS__ is empty: PP_HASCOMMA(__VA_ARGS__) 
      returns 0 andPP_HASCOMMA(PP_COMMA __VA_ARGS__ ()) returns 1.

    2. __VA_ARGS__ contains one argument: 
      PP_HASCOMMA(__VA_ARGS__) returns 0 and
      PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()) returns 0.

    3. __VA_ARGS__ contains two or more arguments: 
      PP_HASCOMMA(__VA_ARGS__) returns 1 and 
      PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()) returns 1.

    The PP_NARG_HELPERx macros are just needed to resolve these cases.

    In order to fix the func(0, ) problem,
    we need to test whether we have supplied zero
    or more arguments. The 
    PP_ISZERO macro comes into play here.

    #define PP_ISZERO(x)    PP_HASCOMMA(PP_ISZERO_HELPER_ ## x)
    #define PP_ISZERO_HELPER_0    ,

    Now let's define another macro which prepends
    the number of arguments to an argument list:

    #define PP_PREPEND_NARG(...)                               \
              PP_PREPEND_NARG_HELPER1(PP_NARG(__VA_ARGS__), __VA_ARGS__)
    #define PP_PREPEND_NARG_HELPER1(N, ...)                    \
              PP_PREPEND_NARG_HELPER2(PP_ISZERO(N), N, __VA_ARGS__)
    #define PP_PREPEND_NARG_HELPER2(z, N, ...)                 \
              PP_PREPEND_NARG_HELPER3(z, N, __VA_ARGS__)
    #define PP_PREPEND_NARG_HELPER3(z, N, ...)                 \
              PP_PREPEND_NARG_HELPER4_ ## z (N, __VA_ARGS__)
    #define PP_PREPEND_NARG_HELPER4_1(N, ...)  0
    #define PP_PREPEND_NARG_HELPER4_0(N, ...)  N, __VA_ARGS__

    The many helpers are again needed to expand
    the macros to numeric values. Finally test it:

    #define my_func(...)  func(PP_PREPEND_NARG(__VA_ARGS__))
    
    my_func()          // expands to func(0)
    my_func(x)         // expands to func(1, x)
    my_func(x, y)      // expands to func(2, x, y)
    my_func(x, y, z)   // expands to func(3, x, y, z)

    It is possible to do in GCC using the ##VA_ARGS extension:

    #define PP_ARG_N( \
              _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10, \
             _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
             _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
             _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
             _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
             _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
             _61, _62, _63, N, ...) N
    
    /* Note 63 is removed */
    #define PP_RSEQ_N()                                        \
             62, 61, 60,                                       \
             59, 58, 57, 56, 55, 54, 53, 52, 51, 50,           \
             49, 48, 47, 46, 45, 44, 43, 42, 41, 40,           \
             39, 38, 37, 36, 35, 34, 33, 32, 31, 30,           \
             29, 28, 27, 26, 25, 24, 23, 22, 21, 20,           \
             19, 18, 17, 16, 15, 14, 13, 12, 11, 10,           \
              9,  8,  7,  6,  5,  4,  3,  2,  1,  0
    
    #define PP_NARG_(...)    PP_ARG_N(__VA_ARGS__)    
    
    /* Note dummy first argument _ and ##__VA_ARGS__ instead of __VA_ARGS__ */
    #define PP_NARG(...)     PP_NARG_(_, ##__VA_ARGS__, PP_RSEQ_N())
    
    #define my_func(...)     func(PP_NARG(__VA_ARGS__), __VA_ARGS__)

    Now PP_NARG(a, b, c) gives 3 and PP_NARG() gives 0.

    Unfortunately I don't see a way to make it work in general.

    I came up with the following workaround for PP_NARG:

    #define PP_NARG(...)     (sizeof(#__VA_ARGS__) - 1 ?       \
        PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) : 0)

    It stringifies __VA_ARGS__, so if it's empty its length equals 1
    (because#__VA_ARGS__ == '\0').
    It works with -std=c99 -pedantic.

    I still have problems with wrapping the variadic function though.
    When__VA_ARGS__ is empty, my_func expands to func(0, ) 
    which triggers a compilation error.

    I usually use this macro to find a number of params:

    #define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))

    So in case of GCC you need to define macros like this:

    #define       NUMARGS(...)  (sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1)
    #define       SUM(...)  sum(NUMARGS(__VA_ARGS__), ##__VA_ARGS__)

    counting args with C macros

    /**
     * we need a placeholder at the start for zero so ##_VA_ARGS__ has something to consume
     * then the arguments are pushed out in such a way that 'cnt' ends up with the right count.
     */
    #define COUNT_ARGS(...) COUNT_ARGS_(Z,##__VA_ARGS__,6,5,4,3,2,1,0)
    #define COUNT_ARGS_(z,a,b,c,d,e,f,cnt,...) cnt
    
    #define C_ASSERT(test) \
        switch(0) {\
          case 0:\
          case test:;\
        }
    
    int main() {
       C_ASSERT(0 ==  COUNT_ARGS());
       C_ASSERT(1 ==  COUNT_ARGS(a));
       C_ASSERT(2 ==  COUNT_ARGS(a,b));
       C_ASSERT(3 ==  COUNT_ARGS(a,b,c));
       C_ASSERT(4 ==  COUNT_ARGS(a,b,c,d));
       C_ASSERT(5 ==  COUNT_ARGS(a,b,c,d,e));
       C_ASSERT(6 ==  COUNT_ARGS(a,b,c,d,e,f));
    }


  • 相关阅读:
    JAVA URI URL 区别
    超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享
    开源框架:Apache的DBUtils框架
    java url openConnection get post 请求
    java 使用jxl poi 操作excel
    如何用Curl 来post xml 数据
    Linux Shell脚本编程--Linux特殊符号大全
    linux查看各服务状态以及开启和关闭
    eclipse中点不出来提示
    cocos2dx切换场景
  • 原文地址:https://www.cnblogs.com/shangdawei/p/3129233.html
Copyright © 2020-2023  润新知