如何确定va_list是否为空

How to determine if va_list is empty

本文关键字:是否 list 何确定 va      更新时间:2023-10-16

我读到一些编译器支持带有宏的va_list,用户可以用其他宏重载该功能以计算va_list。

有了visualstudio,有没有办法确定va_list是否为空(也就是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 )

我在考虑加入一个终止符,但我希望它对调用者隐藏起来,这样现有的代码就不需要更改了。

无法判断有多少参数通过...,也无法判断它们是什么类型。只有当您有其他方式(例如printf风格的格式字符串)来告诉函数期望什么时,才能使用变分函数参数;即便如此,也无法验证这些论点。

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

我意识到这个问题已经很老了,但我认为稍微充实一下可能会有所帮助。正如Mike Seymour非常正确地回答的那样,没有绝对可靠的方法来确定va_list中的自变量数量。这就是为什么定义可变函数的传统方法是包括一个具有该信息的参数,比如:void func(const char *str, int count, ...);,它定义了调用者应该遵守的合同

EDIT:对于变量参数列表末尾之后的任何调用,标准(7.16.1.1.3)实际上对va_arg(vl, type)返回的值保持沉默。大多数类型最常见的情况是类型为零。然而,CAVEAT EMPTOR——它不一定是。

当不再有参数时,从va_arg(vl, type)返回的值是类型化的零值。对于数字类型,它是0。对于指针,它是一个NULL指针。对于structs,它是一个所有字段都为零的structs。如果您选择复制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或零值。无论哪种方式,您都必须理解variadic函数的调用者有责任遵守所声明的契约。所以,编写你的函数,发布契约,然后睡个安稳觉。

我知道我的答案不是"正统"答案,但由于va_list宏的限制,我找到了以下解决方案。我们可以将va_list看作是一个字符数组,更好的是,它是一个以null结尾的字符数组,因此您可以尝试

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

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

相关文章: