将va_list或指针传递给va_list?

时间:2010-07-30 07:53:11

标签: c

假设我有一个函数,它接受从另一个这样的函数传递的可变参数(...)或va_list。主要逻辑是在这个函数本身(让我们称之为f1),但我希望它将va_list传递给另一个函数(让我们称之为f2),这将确定下一个函数参数类型,使用va_arg获取它,并正确转换并存储它以供调用者使用。

将va_list传递给f2是否足够,或者是否需要将指针传递给va_list。除非va_list需要是数组类型或者将其位置数据存储在va_list对象指向的位置(而不是在对象本身中),否则我无法看到如何通过值传递它可以允许调用函数(f1)来“查看”va_arg所调用函数所做的更改。

任何人都可以对此有所了解吗?我对标准要求的内容感兴趣,而不是某些特定实现允许的内容。

6 个答案:

答案 0 :(得分:25)

看起来您需要将指针传递给va_list。有关详细信息,请参阅C99 standard document部分7.15。特别是,第3点要点:

  

对象ap可以作为参数传递给   另一个功能;如果该函数使用参数ap,调用va_arg宏   调用函数中ap的值是不确定的,并应传递给va_end   在进一步提及ap之前的宏

[my italics]

编辑:注意到标准中的一个脚注:

  

215)允许创建指向va_list的指针并将该指针传递给另一个函数,在该函数中   如果原始函数在其他函数返回后可以进一步使用原始列表

因此,您可以将指针传递给va_list并在被调用函数中执行va_arg(*va_list_pointer)

答案 1 :(得分:2)

根据我的理解,你应该直接传递va_list(而不是指向它的指针)。这似乎得到了comp.lang.c

的支持
  

“va_list本身不是一个变量参数列表;它实际上是一个指向一个的指针。也就是说,接受va_list的函数本身不是varargs,反之亦然。”

答案 2 :(得分:2)

我觉得这个问题在这个问题上很模糊。最简单的可能是在标准中查看具有va_list的预定义函数应该如何接收它,例如vsnprintf。这显然是有价值的,而不是参考。

答案 3 :(得分:0)

标准C库中的函数通过va_list元素本身(man 3 vprintf):

   #include <stdarg.h>

   int vprintf(const char *format, va_list ap);
   int vfprintf(FILE *stream, const char *format, va_list ap);
   int vsprintf(char *str, const char *format, va_list ap);
   int vsnprintf(char *str, size_t size, const char *format, va_list ap);

答案 4 :(得分:0)

将指针传递给va_list在32位系统中正常工作。您甚至可以在子例程中一次获取一个参数。 但它似乎不适用于64位系统,会在va_arg()处产生段故障。

答案 5 :(得分:0)

如果要在子函数中使用它,则应传递一个指向va_list的指针,然后不必立即将其传递给va_end。从C99:

  

允许创建指向va_list的指针并将该指针传递给另一个函数,在这种情况下,原始函数可以在另一个函数返回后进一步使用原始列表。

标准允许这样做,但是,在va_list是数组类型的某些64位平台上,此方法不起作用。由于数组的地址与数组的第一个元素的地址相同,因此在调用va_list并将其指针指向va_arg的情况下,传递指向va_list的指针将导致段错误。论点。

一种解决方法是,将va_list作为非常规参数名称(通常后缀一个或多个下划线),然后创建一个新的本地va_list,如下所示:

#include <stdarg.h>

int vfoo(va_list ap_)
{
    int ret;
    va_list ap;
    va_copy(ap, ap_);
    ret = vbar(&ap);
    /* do other stuff with ap */
    va_end(ap);
    return ret;
}

这是我在vsnprintf实现中使用的从其中调用其他函数进行格式化的方法。