std::string 和 stdarg.h

发布于 2025-01-01 17:00:24 字数 1903 浏览 0 评论 0原文

我编写了一个函数,它尝试通过返回 std::string 而不是写入用户提供的 char* 来执行自动分配 sprintf。 (拜托,没有推荐 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;
}

(是的,我看到了管道 a 的讽刺意味C 格式的字符串到 C++ iostream。这只是测试代码。)

不幸的是,使用 VS2008,它在 printf 内部深处崩溃了,显然是因为它读取了错误的参数。 va_list(根据调试器的说法,在 va_start 之后,它指向“真实”第一个参数之前的一个四字节空序列)。

特别值得注意的是,如果在可变参数函数中我更改了 const std::string& format 为 std::string format (即按值传递),它可以正常工作;当然,如果我将其更改为 const char *,它也会这样做。

这是某种编译器错误,还是使用带有引用参数的 va_list 不合法?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小兔几 2025-01-08 17:00:24

我认为如果你想通过推荐信你就运气不好了。以下是 C++2011 标准对 18.10 [support.runtime] 第 3 段中的主题的说明:

ISO C 对标头中 va_start() 宏的第二个参数的限制与此国际标准不同。参数 parmN 是函数定义的变量参数列表中最右边参数的标识符(紧接在 ... 之前的那个)。230 如果参数 parmN 是使用函数、数组或引用类型声明的,或者使用如果类型与传递没有参数的参数时产生的类型不兼容,则行为未定义。

I think you are out of luck if you want to pass a reference. Here is what the C++2011 standard has to say about the subject in 18.10 [support.runtime] paragraph 3:

The restrictions that ISO C places on the second parameter to the va_start() macro in header are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...).230 If the parameter parmN is declared with a function, array, or reference type, or with a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文