Rod*_*ddy 29 c++ reference variadic-functions
我有这段代码(总结)......
AnsiString working(AnsiString format,...)
{
va_list argptr;
AnsiString buff;
va_start(argptr, format);
buff.vprintf(format.c_str(), argptr);
va_end(argptr);
return buff;
}
Run Code Online (Sandbox Code Playgroud)
并且,在可能的情况下优先考虑通过参考,我因此改变了它.
AnsiString broken(const AnsiString &format,...)
{
... the rest, totally identical ...
}
Run Code Online (Sandbox Code Playgroud)
我的主叫代码是这样的: -
AnsiString s1, s2;
s1 = working("Hello %s", "World");
s2 = broken("Hello %s", "World");
Run Code Online (Sandbox Code Playgroud)
但是,s1包含"Hello World",而s2包含"Hello(null)".我认为这是由于va_start的工作方式,但我不确定是怎么回事.
Ecl*_*pse 40
如果你看看va_start扩展到什么,你会看到发生了什么:
va_start(argptr, format);
Run Code Online (Sandbox Code Playgroud)
变得(大致)
argptr = (va_list) (&format+1);
Run Code Online (Sandbox Code Playgroud)
如果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");
Run Code Online (Sandbox Code Playgroud)
要么
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");
Run Code Online (Sandbox Code Playgroud)
Mic*_*urr 14
这是C++标准(18.7 - 其他运行时支持)所说的va_start()
(强调我的):
ISO C对
va_start()
标头<stdarg.h>
中宏 的第二个参数的限制 在本国际标准中是不同的.该参数parmN
是函数定义的变量参数列表中最右边的参数的标识符(前一个参数...
). 如果parmN
使用函数,数组或引用类型声明参数,或者使用与传递没有参数的参数时生成的类型不兼容的类型,则行为未定义.
正如其他人所提到的,如果你将它与非直接C项一起使用(甚至可能以其他方式使用),那么在C++中使用varargs是危险的.
那说 - 我仍然一直使用printf()...