假设我有一个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);
 }

当前回答

在华丽的c++ 11中,你可以使用可变模板:

template <typename... Ts>
void format_string(char *fmt, Ts ... ts) {}

template <typename... Ts>
void debug_print(int dbg_lvl, char *fmt, Ts... ts)
{
  format_string(fmt, ts...);
}

其他回答

我不确定这是否适用于所有编译器,但到目前为止对我来说是有效的。

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()的堆栈地址中读取。因此,只有当两个函数使用相同的堆栈段时,它才有效。

如果你给va_start和va_arg宏一个变量作为起始点,它们通常会工作。如果你愿意,你也可以把指针传递给其他函数。您可以很容易地创建自己的宏。宏所做的就是对内存地址进行类型转换。然而,让它们适用于所有编译器和调用约定是很烦人的。所以使用编译器自带的通常更容易。

假设你写了一个典型的变进函数。因为在可变参数之前至少需要一个参数…,你必须总是在使用中写一个额外的参数。

还是你呢?

如果将可变参数函数包装在宏中,则不需要前面的参数。想想这个例子:

#define LOGI(...)
    ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))

这显然要方便得多,因为您不需要每次都指定初始参数。

罗斯的解决方案清理了一点。只有当所有参数都是指针时才有效。此外,如果__VA_ARGS__为空,语言实现必须支持省略前面的逗号(Visual Studio c++和GCC都支持)。

// 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);}

变进函数是危险的。这里有一个更安全的技巧:

   void func(type* values) {
        while(*values) {
            x = *values++;
            /* do whatever with x */
        }
    }

func((type[]){val1,val2,val3,val4,0});

可以对函数调用使用内联汇编。(在这段代码中,我假设参数是字符)。

void format_string(char *fmt, ...);
void debug_print(int dbg_level, int numOfArgs, char *fmt, ...)
    {
        va_list argumentsToPass;
        va_start(argumentsToPass, fmt);
        char *list = new char[numOfArgs];
        for(int n = 0; n < numOfArgs; n++)
            list[n] = va_arg(argumentsToPass, char);
        va_end(argumentsToPass);
        for(int n = numOfArgs - 1; n >= 0; n--)
        {
            char next;
            next = list[n];
            __asm push next;
        }
        __asm push fmt;
        __asm call format_string;
        fprintf(stdout, fmt);
    }