【问题标题】:Count number of parameters in C variable argument method call计算 C 变量参数方法调用中的参数个数
【发布时间】:2011-04-21 13:31:22
【问题描述】:

当使用 va_start()、va_arg() 和 va_end() 读取传递给方法的参数时,有没有办法计算参数的数量?

根据手册页,如果你调用 va_arg() 太多次你会得到“随机错误”:

如果没有下一个参数,或者如果 类型与类型不兼容 实际的下一个参数(如 按照默认提升 参数提升),会出现随机错误。

【问题讨论】:

标签: c gcc variadic-functions


【解决方案1】:

没有。变量参数函数(例如printf)必须“知道”何时停止寻找更多参数。

printf 知道其格式字符串中%d%s 和其他符号的数量。

其他函数有时会使用 Sentinel 值:

sumValues(1, 3, 5, 7, 6, 9, -1); // will add numbers until it encounters a -1

其他函数可能有预先说明的参数数量:

AddNames(4, "Bill", "Alice", "Mike", "Tom");

【讨论】:

    【解决方案2】:

    有两种方法可以知道传递了多少参数。首先,您可以让其中一个函数参数告诉您(例如printf)。另一种方法是在列表末尾添加一个标记值 - 例如,您可以在 NULL 参数处停止。

    如果您选择第二种方法,您可以使用va_copy,但仍想在决定如何处理参数之前计算参数。

    【讨论】:

      【解决方案3】:

      这是一个相当惊人的技巧,它允许您使用 C99 的可变参数宏构建您想要的东西:

      PP_NARG()
      返回__VA_ARGS__中包含的参数个数

      您可以使用它来编写一个包装您的真实函数的宏,该宏在真实函数的参数前面添加一个计数。

      另见this question。然而,可能经典方法在一三年内仍然更明智!


      代码,因此即使没有 Usenet 存档,此答案也很有用...

      /* The PP_NARG macro returns the number of arguments that have been
        * passed to it.
        */
      
      #define PP_NARG(...) \
               PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
      #define PP_NARG_(...) \
               PP_ARG_N(__VA_ARGS__)
      #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 
      

      【讨论】:

      • 我应该说这很可爱 :-) 很好的发现!
      • 正是我要说的!
      • P99 将有一组受此启发的宏,这可能正是您所需要的。不幸的是,该版本只会在一周内发布,但如果您想查看文档:p99.gforge.inria.fr/p99-html/group__variadic.html
      • @Jens:乍一看,P99 文档看起来很有趣,但是当我看到这一点时,我宁愿失去进一步阅读的兴趣:“这个文件是 P99 项目的一部分。你收到了此文件作为机密协议的一部分,您通常不得重新分发和/或修改它,除非根据文件 LICENSE 中给出的条款。”没有保密协议,文档网站上也没有 LICENSE 文件,而且我通常对无法修改的东西不感兴趣。
      • @John:我完全同意。这个许可证将会改变,这实际上是 P99 尚未发布的原因:我正在与我的层次结构讨论选择哪个许可证。可能它会类似于 LGPL。但是在法国,程序很慢。
      【解决方案4】:

      对可变参数函数的哨兵版本的一个方便的变体是定义一个宏,该宏会自动将预期的哨兵作为最后一个参数相加:

      #include <stdarg.h>
      #include <assert.h>
      
      int sum_(int unused, ...)
      {
        va_list args;
        int sum, val;
      
        va_start(args, unused);
        
        sum = 0;
        while ((val = va_arg(args, int)) != -1)
          sum += val;
      
        va_end(args);
      
        return sum;
      }
      
      #define sum(...) sum_(41, ##__VA_ARGS__, -1)
      
      void main(void)
      {
        assert(sum(1, 2, 3, 4, 5, 6) == 21);
      }
      

      【讨论】:

      • 41 应该是 42 :)
      • 一开始是,后来我把它编辑为 41,因为“Sum41”太诱人了 ;-)
      猜你喜欢
      • 1970-01-01
      • 2017-08-24
      • 2011-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      相关资源
      最近更新 更多