将引用作为命名参数传递给可变参数函数的问题

Posted

技术标签:

【中文标题】将引用作为命名参数传递给可变参数函数的问题【英文标题】:Problem passing a reference as a named parameter to a variadic function 【发布时间】:2010-05-17 21:48:44 【问题描述】:

我在 Visual Studio 2003 中遇到以下问题:

void foo(const char*& str, ...) 
    va_list args;
    va_start(args, str);

    const char* foo;
    while((foo = va_arg(args, const char*)) != NULL) 
        printf("%s\n", foo);
    

当我调用它时:

const char* one = "one";
foo(one, "two", "three", NULL);

我明白了:

访问冲突读取位置0xcccccccc

printf() 行——va_arg() 返回 0xcccccccc。我终于发现它的第一个参数是破坏它的引用——如果我把它变成一个普通的 char* 一切都很好。类型是什么似乎并不重要。作为参考会导致它在运行时失败。这是VS2003的一个已知问题,还是有某种合法行为?它不会发生在 GCC 中。我尚未使用较新的 Visual Studio 进行测试以查看行为是否消失

【问题讨论】:

【参考方案1】:

VS2005 也崩溃了。

问题在于 va_start 使用给它的参数的地址,并且由于 str 是一个引用,它的地址是定义在调用者中的“one”变量的地址,而不是堆栈上的地址。

我看不到获取堆栈变量地址的方法(实际上包含正在传递的“一个”的地址的参数),但有一些解决方法:

使用“const char *str”或“const char **str”代替“const char * &str” 将下一个参数也添加到“固定”参数列表中

这段代码说明了第二种选择:

void foo(const char* &str, const char *arg1, ...) 
    if (arg1) 
       va_list args;
       va_start(args, arg1);
       printf ("%s\n", arg1);
       const char* foo;
       while((foo = va_arg(args, const char*)) != NULL) 
           printf("%s\n", foo);
       
    

【讨论】:

哦,回想起来真的很明显;我猜 glibc 对 va_start 的实现不依赖于最终命名参数的地址,它以其他方式计算出 ... 的开始 刚刚在velocityreviews.com/forums/t281115-va_start-and-references.html 发现不允许在引用上使用 va_start。另见***.com/questions/222195/…。 刚刚搜索过“va_arg reference C++”,等等。

以上是关于将引用作为命名参数传递给可变参数函数的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jquery 将可变参数传递给匿名函数?

如何循环遍历动态大小的数组并将属性作为参数传递给可变参数函数?

怎么将可变参数的函数的参数传递给另一个可变参数的函数

将可变参数函数模板参数传递给另一个函数

可以将可变数量的参数传递给函数吗?

将可变数量的 bash 命令行参数传递给 MATLAB 函数