varargs(va_list va_start)不适用于pass-by-reference参数

时间:2010-07-06 07:46:03

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

  

可能重复:
  Are there gotchas using varargs with reference parameters

嗨,我的varargs有问题。 查看我的代码(Microsoft Visual Studio 2005或2008)。

#include <stdarg.h>

struct Test { int a; };

void T1(int n, ...) {
 va_list args;
 va_start(args, n);
 char* p = va_arg(args, char*);
 va_end(args);
}

void T2(Test n, ...) {
 va_list args;
 va_start(args, n);
 char* p = va_arg(args, char*);
 va_end(args);
}

void T3(const Test& n, ...) {
 va_list args;
 va_start(args, n);
 char* p = va_arg(args, char*);  // p corrupt!!
 va_end(args);
}

int _tmain(int argc, _TCHAR* argv[]) {
 const Test t;
 T1(1, "Test1");
 T2(t, "Test2");
 T3(t, "Test3");
 return 0;
}

功能T1,T2运行良好。但T3功能有问题。指针p不指向“Test3”。我不能将va_start与pass-by-reference一起使用吗? 提前谢谢。

2 个答案:

答案 0 :(得分:13)

根据C ++标准18.7 / 3,您不能使用va_start的引用:

  

ISO C对标头中va_start()宏的第二个参数的限制    在这个国际标准中有所不同。参数parmN是。的标识符   函数定义的变量参数列表中最右边的参数(就在...之前的那个)。   如果参数parmN使用函数,数组或引用类型声明,或者使用不兼容的类型声明   使用在传递没有参数的参数时得到的类型,行为是   未定义。

答案 1 :(得分:4)

简短回答:不,你做不到。

注意:我看到第一个引用标准的答案,但我相信值得展示我的测试。

va_start的定义如下:

视觉6:#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

视觉8:#define _crt_va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \ __alignof(v), _ADDRESSOF(v)) )

使用此代码:

#include <cstdio>

int main()
{
    char c;
    char &rc = c;
    int i;
    int &ri = i;

    printf("char ref:%d\n", sizeof(rc));
    printf("int ref:%d\n", sizeof(ri));

    return 0;
}

输出

char ref:1
int ref:4

由于在实现级别引用以与指针类似的方式在堆栈上传递,这表示一个问题,因为大小不同(这是因为宏计算了类型的大小而没有考虑参数实际上是引用,它不是常数,而是取决于类型的实际大小。)