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兼容语法,该怎么办?

最佳答案

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

Windows提供了_vsnprintf_s函数,该函数已经类似于vsnprintf,但是在提供的缓冲区太小时会发生以下重要变化:

  • 缓冲区内容取决于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,它看起来更适合此实现,但它不会终止生成的字符串。如果要使用它,应该小心。

    08-16 21:47