私はこのコードを持っています(要約)...
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 = working("Hello %s", "World"); // prints "Hello World"
AnsiString s2 = broken("Hello %s", "World"); // prints "Hello (null)"
これは動作の仕方によるものだと思いますva_start
が、何が起こっているのか正確にはわかりません。
ベストアンサー1
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");