当前位置:  开发笔记 > 编程语言 > 正文

有没有使用带参考参数的varargs

如何解决《有没有使用带参考参数的varargs》经验,为你挑选了2个好方法。

我有这段代码(总结)......

AnsiString working(AnsiString format,...)
{
    va_list argptr;
    AnsiString buff;

    va_start(argptr, format);
    buff.vprintf(format.c_str(), argptr);

    va_end(argptr);
    return buff;
}

并且,在可能的情况下优先考虑通过参考,我因此改变了它.

AnsiString broken(const AnsiString &format,...)
{
... the rest, totally identical ...
}

我的主叫代码是这样的: -

AnsiString s1, s2;
    s1 = working("Hello %s", "World");
    s2 = broken("Hello %s", "World");

但是,s1包含"Hello World",而s2包含"Hello(null)".我认为这是由于va_start的工作方式,但我不确定是怎么回事.



1> Eclipse..:

如果你看看va_start扩展到什么,你会看到发生了什么:

va_start(argptr, format); 

变得(大致)

argptr = (va_list) (&format+1);

如果format是值类型,它将在所有可变参数之前放置在堆栈上.如果format是引用类型,则只有地址放在堆栈上.当你获取引用变量的地址时,你得到地址或原始变量(在这种情况下是在调用Broken之前创建的临时AnsiString),而不是参数的地址.

如果你不想传递完整的类,你的选择是通过指针传递,或者放入一个伪参数:

AnsiString working_ptr(const AnsiString *format,...)
{
    ASSERT(format != NULL);
    va_list argptr;
    AnsiString buff;

    va_start(argptr, format);
    buff.vprintf(format->c_str(), argptr);

    va_end(argptr);
    return buff;
}

...

AnsiString format = "Hello %s";
s1 = working_ptr(&format, "World");

要么

AnsiString working_dummy(const AnsiString &format, int dummy, ...)
{
    va_list argptr;
    AnsiString buff;

    va_start(argptr, dummy);
    buff.vprintf(format.c_str(), argptr);

    va_end(argptr);
    return buff;
}

...

s1 = working_dummy("Hello %s", 0, "World");


这是众所周知的漏洞抽象的一个很好的例子.va_start看起来像某种神奇的东西,但实际上它只是一些编译器批准的hackery.
很好地解释了发生了什么.

2> Michael Burr..:

这是C++标准(18.7 - 其他运行时支持)所说的va_start()(强调我的):

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

正如其他人所提到的,如果你将它与非直接C项一起使用(甚至可能以其他方式使用),那么在C++中使用varargs是危险的.

那说 - 我仍然一直使用printf()...

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有