如何在C ++ 03中用sprintf正确替换sprintf_s?

时间:2019-01-17 14:57:10

标签: c++ printf posix c++03

sprintf_s是Microsoft函数sprintf的实现,其中他们修补了一个缺陷,并添加了一个参数以取一个边界值,其中该函数只能写。

C++11中引入了等效项:snprintf。但是在这里,我们谈论的是C++03语法。

签名:

count_char_written sprintf(char* string_out, const char* output_template, VARIADIC_ARGS);
// and
count_char_written sprintf_s(char* string_out, size_t buffer_max_size, const char* output_template, VARIADIC_ARGS);

在功能上,sprintf_ssprintf更先进,因为它避免了溢出。 但是sprintf_s仅适用于Microsoft!

如果要将使用C++03编写的sprintf_s代码移植回POSIX兼容语法该怎么办?

1 个答案:

答案 0 :(得分:2)

今天,snprintfvsnprintf都应随处可用,但MSVC12和更早版本的Windows除外。最简单的方法是在不可用的Windows上提供snprintf / vsnprintf

Windows提供的功能_vsnprintf_svsnprintf类似,但是在提供缓冲区太小时会发生以下重要变化:

  • 缓冲区内容取决于count中不存在的附加vsnprintf参数。要获得vsnprintf的行为,您可以在此处传递_TRUNCATE
  • 返回
  • -1而不是所需的字符数。可以使用_vscprintf函数来解决此问题,该函数仅在先前对_vsnprintf_s的调用失败时才需要调用。

此外,这些功能不支持C99中添加的格式说明符,例如%zd。这不能轻易解决,您将不得不避免使用它们。

以下代码:

int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
    int r = -1;

    if (size != 0)
    {
        va_list args_copy;
        va_copy(args_copy, args);
        r = _vsnprintf_s(buf, size, _TRUNCATE, fmt, args_copy);
        va_end(args_copy);
    }

    if (r == -1)
    {
        r = _vscprintf(fmt, args);
    }

    return r;
}

int snprintf(char *buf, size_t size, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    int r = vsnprintf(buf, size, fmt, args);
    va_end(args);
    return r;
}

注意:Windows还提供了_vsnprintf,它看起来更适合此实现,但是它不会终止结果字符串。如果要使用它,请务必小心。