I have written a function which tries to do an auto-allocating sprintf by returning a std::string instead of writing into a user-supplied char*
. (Please, no answers recommending iostreams or Boost.Format or friends -- I know they exist, I do use them in other contexts, but there is a requirement for this particular case.)
std::string FormatString(const std::string& format, va_list argList)
{
char smallBuffer[500], *text = smallBuffer;
int length = _countof(smallBuffer);
// MSVC is not C99 conformant, so its vsnprintf returns -1
// on insufficient buffer space
int outputSize = _vsnprintf(text, length, format.c_str(), argList);
while (outputSize < 0 && errno == ERANGE && length > 0)
{
length <<= 1;
if (text != smallBuffer) { delete[] text; }
text = new char[length];
outputSize = _vsnprintf(text, length, format.c_str(), argList);
}
if (outputSize < 0)
{
throw std::runtime_error("Failed to format string.");
}
std::string ret(text);
if (text != smallBuffer)
{
delete[] text;
}
return ret;
}
std::string FormatString(const std::string& format, ...)
{
va_list argList;
va_start(argList, format);
std::string result;
try
{
result = FormatString(format, argList);
}
catch(...)
{
va_end(argList);
throw;
}
va_end(argList);
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int foo = 1234;
std::string bar = "BlaBla";
std::cout << FormatString("%i (%s)", foo, bar.c_str()) << std::endl;
return 0;
}
(And yes, I see the irony of piping a C-formatted string to a C++ iostream. This is just test code.)
Unfortunately, using VS2008, it's crashing deep within the bowels of the printf internals, apparently because it's reading the wrong arguments out of the va_list
(according to the debugger, after the va_start
it's pointing at a four-byte null sequence immediately prior to the "real" first parameter).
Of particular note is that if in the variadic function I change the const std::string& format
to just std::string format
(ie. pass by value), it works properly; it also does so if I change it to a const char *
, of course.
Is this some sort of compiler bug, or is it not legal to use a va_list with reference parameters?