【发布时间】:2011-04-21 13:31:22
【问题描述】:
当使用 va_start()、va_arg() 和 va_end() 读取传递给方法的参数时,有没有办法计算参数的数量?
根据手册页,如果你调用 va_arg() 太多次你会得到“随机错误”:
如果没有下一个参数,或者如果 类型与类型不兼容 实际的下一个参数(如 按照默认提升 参数提升),会出现随机错误。
【问题讨论】:
标签: c gcc variadic-functions
当使用 va_start()、va_arg() 和 va_end() 读取传递给方法的参数时,有没有办法计算参数的数量?
根据手册页,如果你调用 va_arg() 太多次你会得到“随机错误”:
如果没有下一个参数,或者如果 类型与类型不兼容 实际的下一个参数(如 按照默认提升 参数提升),会出现随机错误。
【问题讨论】:
标签: c gcc variadic-functions
没有。变量参数函数(例如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");
【讨论】:
有两种方法可以知道传递了多少参数。首先,您可以让其中一个函数参数告诉您(例如printf)。另一种方法是在列表末尾添加一个标记值 - 例如,您可以在 NULL 参数处停止。
如果您选择第二种方法,您可以使用va_copy,但仍想在决定如何处理参数之前计算参数。
【讨论】:
这是一个相当惊人的技巧,它允许您使用 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
【讨论】:
对可变参数函数的哨兵版本的一个方便的变体是定义一个宏,该宏会自动将预期的哨兵作为最后一个参数相加:
#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);
}
【讨论】: