7

我一直在阅读一些编译器支持带有宏的 va_list ,并且用户能够使用其他宏重载该功能以计算 va_list

使用 Visual Studio,有没有办法确定 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 仅将参数设置为空。

#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 )

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

4

3 回答 3

7

没有办法知道传递了多少参数...,也不知道它们是什么类型。仅当您有其他方式(例如printf-style 格式字符串)来告诉函数期望什么时,才能使用可变函数参数;即便如此,也无法验证这些论点。

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

于 2012-07-25T15:42:52.940 回答
0

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

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

va_arg(vl, type)当没有更多参数时返回的值是一个类型为零的值。对于数字类型,它是 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 或零值。无论哪种方式,您都必须了解可变参数函数的调用者有责任遵守规定的合同。因此,编写您的函数,发布合约,然后轻松入睡。

于 2017-06-10T01:12:03.877 回答
-2

我知道我的答案不是“正统”答案,但是由于va_list宏的限制,我发现以下解决方案可行。我们可以将 va_list 视为一个字符数组,甚至更好的是一个以 null 结尾的字符,因此您可以尝试

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

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

于 2017-12-29T12:36:45.090 回答