我想编写一个C函数,它可以接受任意数量的参数并仅打印int
个参数的值。我在va_list
中看到va_arg
和stdarg.h
,但我找不到任何获取参数数量的机制。我不能把第一个参数作为参数的数量。
答案 0 :(得分:2)
标准C中没有可移植的方法来获取变量参数函数中的参数数量。
解决它的常用方法是使用最右边的参数parmN
来明确提供整数的数量。例如,您的函数原型可能如下所示:
int foo(int number, ...);
但根据你的问题,这不是你的选择。
参考:C FAQ: How can I discover how many arguments a function was actually called with?
答案 1 :(得分:1)
没有(可移植)方法可以在运行时获取可变参数函数中的参数数量。该数字在运行时丢失(只有编译器才知道)。
请注意,在常见处理器和application binary interfaces(ABI)约定(例如Linux上的x86-64 ABI)上,机器本身在运行时不知道C中当前调用的arity;其他人x86 calling conventions也是如此。但是,当编译器正在编译一个可变参数调用时,它确实在编译时知道arity(但不会在目标文件中发出它)。
您可以定义变量函数作为第一个参数作为剩余(可变参数)参数的数量的约定:
void print_integers (int nbints, ...);
然后你会实现它,例如
#include <stdio.h>
#include <stdarg.h>
void print_integers (int nbints, ...)
{
va_list args;
va_start (nbints, args);
for (int ix=0; ix<nbints; ix++) {
int curarg = va_arg(args, int);
printf(" %d", curarg);
};
va_end(args);
fflush(NULL);
}
如果您不能这样做,则必须自定义预处理器或编译器。也许MELT扩展的作业( MELT 是扩展GCC的域特定语言)。或者使用GPP作为预处理器。
您还可以播放一些cpp预处理器技巧,特别是stringification和concatenation以及variadic macros。例如,您可以定义
void print_integers_str(const char*, ...);
#define print_my_integers(...) \
print_integers_str(#__VA_ARGS__, ##__VA_ARGS__);
然后print_my_integers(x,y)
扩展为print_integers_str("x,y", x,y)
,你的varadic函数print_integer_str
可以解析"x,y"
文字字符串(至少计算逗号)。但是print_my_integers(f(x,y),g(y)+/*,,*/k)
你可能会遇到噩梦。
要简短:我建议放弃这个目标并做其他事情。
答案 2 :(得分:0)
使用NARGS宏(在这种情况下限制为8个args):
#include <stdio.h>
#include <stdarg.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define fn(...) fn(NARGS(__VA_ARGS__), __VA_ARGS__)
static void (fn)(int n, ...)
{
va_list args;
int i;
va_start(args, n);
for (i = 0; i < n; i++) {
printf("%d\n", va_arg(args, int));
}
va_end(args);
}
int main(void)
{
fn(6, 7, 8);
return 0;
}
或者你可以循环直到-1:
#include <stdio.h>
#include <stdarg.h>
#define fn(...) fn(0, __VA_ARGS__, -1)
static void (fn)(int n, ...)
{
va_list args;
int i;
va_start(args, n);
while (1) {
i = va_arg(args, int);
if (i == -1) break;
printf("%d\n", i);
}
va_end(args);
}
int main(void)
{
fn(6, 7, 8);
return 0;
}