具有类引用作为第一参数的变量参数

时间:2010-01-21 03:45:05

标签: c++

我有以下代码:

#include <cstdarg>
#include <iostream>

using namespace std;

class a {
};

void fun1(a& aa, ...)
{
    va_list argp;
    va_start(argp, aa);
    char *p = 0;
    while ((p = va_arg(argp, char *)) != 0) {
        cout << p << endl;
    }
    va_end(argp);
}

void fun2(char *aa, ...)
{
    va_list argp;
    va_start(argp, aa);
    char *p = 0;
    while ((p = va_arg(argp, char *)) != 0) {
        cout << p << endl;
    }
    va_end(argp);
}

int main()
{
    cout << "fun2" << endl;
    fun2("a", "1", "2", (char *)0);
    cout << "fun1" << endl;
    fun1(a(), "1", "2", (char *)0);
    getchar();
}

一切都很好用fun2。但是,fun1只会崩溃。

我是否知道如何防止崩溃,同时能够将类引用用作第一个参数。

目前,它打印:

fun2
1
2
fun1

然后崩溃。

我希望

fun2
1
2
fun1
1
2

5 个答案:

答案 0 :(得分:4)

您不能将引用参数用作va_start的最后一个命名参数。原因是因为va_start获取命名参数的地址以查找其余参数的位置。但是,获取引用的地址会给出引用所指向的变量的地址,而不是参数本身的地址。您的选择是:

1)将变量类型从引用更改为指针(如果您对传入的变量的副本没有问题,则更改非引用)。

2)添加一个额外的必需参数,以使引用不是最后一个命名参数。附加参数可以是一个有用的参数,例如您要传递给特定函数的char *之一,或者它可以是您忽略的虚拟变量。

3)更改va_start的定义。不推荐,但你可以做到。有关非便携式重新定义,请参阅http://support.microsoft.com/kb/119394

答案 1 :(得分:2)

我认为你在fun2崩溃了。

因为你要多次调用va_arg并搞砸了堆栈。

您必须只调用va_arg与参数相同的次数。

答案 2 :(得分:2)

fun1fun2在遇到NULL0参数时都会终止循环。你永远不会传递一个。将main更改为:

int main()
{
    cout << "fun2" << endl;
    fun2("a", "1", "2", NULL);
    cout << "fun1" << endl;
    fun1(a(), "1", "2", NULL);
    getchar();
    return 0;
}

注意我没有编译过这个,但是应该可以。您可能还必须关注janm's advice

更新:我放下并再次考虑这个问题。你必须要么:

  1. a内实例化main类型的对象并将其传递或...
  2. 关注janm's advice并将a& aa中的fun2更改为a const& aa
  3. 当我尝试在g ++下编译原文时,我遇到了以下错误:

      

    错误:'a&amp;'类型的非const引用的初始化无效来自a          暂时的'a'类型   错误:传递'void fun1(a&amp;,...)'

    的参数1

    基本上,您不能将临时变量作为非const引用传递。有关一些血腥的详细信息,请参阅this SO questionthis Herb Sutter GotW

答案 3 :(得分:0)

您正在将非const引用传递给临时引用。将fun1原型更改为:

void fun1(a const& aa, ...)

更新

长时间没有使用varargs,错过了终止参数未通过。见D. Shawley's answer;如果您要将其用作界面,则必须传递终止参数。

答案 4 :(得分:0)

我很遗憾听到这段代码不起作用。我注意到如果fun2(aa是ptr而不是ref代码可以工作。我也注意到在尝试编译gcc时(通过http://codepad.org/)你将“a”传递给fun2,这是一个char * .codepad / gcc抱怨它不是一个常量字符*。在键盘中这个代码有效。在我的VS2008副本中它崩溃了,而且2010b2也是。

我的建议是避免使用va params,但我会假设你不能这样,我建议不要使用ref并使用指针。或者切换到gcc但我不会这样做,除非没有其他(合理的)选项。

#include<cstdlib>
#include <cstdio>
#include <ios>
#include <iostream>
using namespace std;
class a {
};

void fun1(a& aa, ...)
{
    //cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa;
    va_list argp;
    va_start(argp, aa);
    char *p = 0;
    while ((p = va_arg(argp, char *)) != 0) {
        cout << p << endl;
    }
    va_end(argp);
}

void fun2(const char *aa, ...)
{
    va_list argp;
    va_start(argp, aa);
    char *p = 0;
    while ((p = va_arg(argp, char *)) != 0) {
        cout << p << endl;
    }
    va_end(argp);
}

int main()
{
    cout << "fun2" << endl;
    fun2("a", "1", "2", 0);
    cout << "fun1" << endl;
    a aa;
    //cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa;
    fun1(aa, "1", "2", 0);
    getchar();
}