std :: string и stdarg.h - PullRequest
       26

std :: string и stdarg.h

2 голосов
/ 03 февраля 2012

Я написал функцию, которая пытается выполнить автоматическое распределение 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 со ссылочными параметрами?

1 Ответ

3 голосов
/ 03 февраля 2012

Я думаю, что вам не повезло, если вы хотите передать ссылку.Вот что стандарт C ++ 2011 должен сказать о предмете в пункте 18.10 [support.runtime]:

Ограничения, которые ISO C накладывает на второй параметр макроса va_start ()в заголовке отличаются в этом международном стандарте.Параметр parmN является идентификатором самого правого параметра в списке переменных параметров определения функции (тот, что перед ...). 230 Если параметр parmN объявлен с функцией, массивом или ссылочным типом или стип, который не совместим с типом, который получается при передаче аргумента, для которого нет параметра, поведение не определено.

...