Я написал функцию, которая пытается выполнить автоматическое распределение sprintf, возвращая std :: string вместо записи в предоставленный пользователем char*
. (Пожалуйста, без ответов, рекомендующих iostreams или Boost.Format или друзей - я знаю, что они существуют, я использую их в других контекстах, но для этого конкретного случая есть требование.)
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;
}
(И да, я вижу иронию передачи строки в формате C в iostream C ++. Это всего лишь тестовый код.)
К сожалению, при использовании VS2008 он падает глубоко в недрах внутренних компонентов printf, по-видимому, потому что он читает неправильные аргументы из va_list
(согласно отладчику, после va_start
он указывает на четырехбайтовый байт). нулевая последовательность непосредственно перед «реальным» первым параметром).
Особо следует отметить, что если в функции переменной я изменить const std::string& format
на std::string format
(т.е. передать по значению), он будет работать правильно; это также делает, если я изменяю это на const char *
, конечно.
Это какая-то ошибка компилятора или недопустимо использование va_list со ссылочными параметрами?