假设我有一个函数,它接受从另一个这样的函数传递的可变参数(...
)或va_list
。主要逻辑是在这个函数本身(让我们称之为f1
),但我希望它将va_list
传递给另一个函数(让我们称之为f2
),这将确定下一个函数参数类型,使用va_arg
获取它,并正确转换并存储它以供调用者使用。
将va_list传递给f2
是否足够,或者是否需要将指针传递给va_list。除非va_list需要是数组类型或者将其位置数据存储在va_list
对象指向的位置(而不是在对象本身中),否则我无法看到如何通过值传递它可以允许调用函数(f1
)来“查看”va_arg
所调用函数所做的更改。
任何人都可以对此有所了解吗?我对标准要求的内容感兴趣,而不是某些特定实现允许的内容。
答案 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
实现中使用的从其中调用其他函数进行格式化的方法。