假设我有一个带有可变数量参数的C函数:如何调用另一个函数,该函数需要从其内部获取可变数量的参数,并将所有参数传递到第一个函数中?
例:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
#1楼
罗斯的解决方案有点清理干净了。 仅当所有args都是指针时才有效。 如果__VA_ARGS__为空(Visual Studio C ++和GCC都这样做),语言实现也必须支持__VA_ARGS__以前的逗号。
// pass number of arguments version
#define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__}; _actualFunction(args+1,sizeof(args) / sizeof(*args) - 1);}
// NULL terminated array version
#define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__, NULL}; _actualFunction(args+1);}
#2楼
我不确定这是否适用于所有编译器,但它对我来说已经有用了。
void inner_func(int &i)
{
va_list vars;
va_start(vars, i);
int j = va_arg(vars);
va_end(vars); // Generally useless, but should be included.
}
void func(int i, ...)
{
inner_func(i);
}
如果需要,可以将...添加到inner_func(),但不需要它。 它起作用,因为va_start使用给定变量的地址作为起点。 在这种情况下,我们在func()中给它一个变量的引用。 所以它使用该地址并在堆栈之后读取变量。 inner_func()函数从func()的堆栈地址读取。 因此,只有两个函数使用相同的堆栈段时才有效。
如果你给它们任何var作为起点,那么va_start和va_arg宏通常会起作用。 因此,如果您希望您可以将指针传递给其他函数并使用它们。 您可以轻松制作自己的宏。 所有的宏都是类型转换内存地址。 然而,使它们适用于所有编译器和调用约定是令人讨厌的。 因此,使用编译器附带的内容通常更容易。
#3楼
要传递省略号,您必须将它们转换为va_list并在第二个函数中使用该va_list。 特别;
void format_string(char *fmt,va_list argptr, char *formatted_string);
void debug_print(int dbg_lvl, char *fmt, ...)
{
char formatted_string[MAX_FMT_SIZE];
va_list argptr;
va_start(argptr,fmt);
format_string(fmt, argptr, formatted_string);
va_end(argptr);
fprintf(stdout, "%s",formatted_string);
}
#4楼
没有办法调用(例如)printf而不知道你传递了多少个参数,除非你想进入顽皮和非便携的技巧。
通常使用的解决方案是始终提供另一种形式的vararg函数,因此printf具有vprintf ,它使用va_list代替... ...版本只是va_list版本的包装器。
#5楼
你也可以尝试宏。
#define NONE 0x00
#define DBG 0x1F
#define INFO 0x0F
#define ERR 0x07
#define EMR 0x03
#define CRIT 0x01
#define DEBUG_LEVEL ERR
#define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: "
#define WHEREARG __FILE__,__func__,__LINE__
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define DEBUG_PRINT(X, _fmt, ...) if((DEBUG_LEVEL & X) == X) \
DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__)
int main()
{
int x=10;
DEBUG_PRINT(DBG, "i am x %d\n", x);
return 0;
}