如何确定va_list是否为空

时间:2012-07-25 15:22:47

标签: c++ visual-studio-2010 visual-c++ variadic-functions

我一直在读一些编译器支持带宏的va_list,用户能够overload the functionality with other macros in order to count the va_list

使用visual studio,有没有办法确定va_list是否为空(aka count == 0)?基本上我想知道这个条件:

extern void Foo(const char* psz, ...);
void Test()
{
  Foo("My String"); // No params were passed
}

我最初的想法是做这样的事情:

va_list vaStart;
va_list vaEnd;
va_start(vaStart, psz);
va_end(vaEnd);
if (vaStart == vaEnd) ...

问题是va_end只将param设置为null。

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

我在考虑合并一个terminator,但我希望它对调用者隐藏,以便不需要更改现有代码。

3 个答案:

答案 0 :(得分:5)

无法判断通过...传递的参数数量,也不知道它们的类型。变量函数参数只能用于其他方式(例如printf - 样式格式字符串)来告诉函数期望什么;即便如此,也无法验证论点。

C ++ 11提供了类型安全的可变参数模板。我不知道你的编译器是否支持这些,或者它们是否适合你的问题。

答案 1 :(得分:3)

我意识到这个问题相当陈旧,但我认为将它充实一点可能会有所帮助。正如Mike Seymour的回答非常正确,没有绝对可靠的方法来确定va_list中的参数数量。这就是为什么定义可变参数函数的传统方法是包含一个具有该信息的参数,如下所示:void func(const char *str, int count, ...);,它定义了调用者应该遵守的契约。

编辑:标准(7.16.1.1.3)实际上对va_arg(vl, type)为变量参数列表末尾的任何调用返回的值保持沉默。大多数类型最常见的情况是键入零。但是,CAVEAT EMPTOR - 它并非必须如此。

当没有更多参数时,从va_arg(vl, type)返回的值是typed-zero值。对于数字类型,它是0.对于指针,它是一个NULL指针。对于结构体,它是一个结构,所有字段都归零。如果您选择复制va_list并尝试计算副本,请执行以下操作:

void func(const char *str, ...) {
    va_list vl;
    va_list vc;
    int x;
    int count;

    count = 0;
    va_start(vl, str);
    va_copy(vc, vl);
    do {
        x = va_arg(vc, int);
        if (x == 0) break;
        count++;
    } while (1)
    va_end(vc);
    .
    .
    . // do something, or something else,
    . // based on the number of args in the list
    .
    va_end(vl);

您必须假设调用者将遵守合同,不在列表中传递NULL或零值。无论哪种方式,您必须了解可变函数的调用者负责遵守所述合同。所以写下你的功能,发布合同,轻松入睡。

答案 2 :(得分:-2)

我知道我的答案不是“正统”答案,但是由于va_list宏的限制,我发现以下解决方案可行。我们可以将va_list看作一个字符数组,甚至更好,一个空终止字符,所以你可以尝试

va_list argptr;
if(strcmp(argptr,"")) 
{
   // not empty
}
else
{
   // empty
}

我试过了,它对我有用。 我使用的是Visual Studio 2013 Ultimate。项目类型是Win32控制台应用程序。没有编译错误。