【问题标题】:Is vsnprintf_s an appropriate replacement for deprecated vsnprintf?vsnprintf_s 是否适合替代已弃用的 vsnprintf?
【发布时间】:2013-06-27 19:42:43
【问题描述】:

在我的代码(严格的 C,而不是 C++)中,我以这种方式使用 vsnprintf:

char* buf = NULL;
size_t sz;
sz = vsnprintf( buf, 0, format, args); // Ask vsnprintf how big a buffer we need

buf = (char*) malloc(sz + 1);
vsnprintf( buf, sz, format, args); // Now actually fill the buffer
/* Use buf in a dialog box... then: */
free(buf);

但 MS Visual C++ (MSVS10) 编译器会发出警告:

warning C4996: 'vsnprintf': This function or variable may be unsafe. Consider using vsnprintf_s instead. 

然而,vsnprintf_s没有有一个漂亮的特性,当你为缓冲区传递 NULL 时,它将描述它将要打印多少数据。相反,它是documented to return -1

我觉得我通过确定必要的大小以安全的方式使用vsnprintf,并且推荐的替换vsnprintf_s 根本不一样。

我是否错过了使用vsnprintf_s 的更好/更智能的方式??

【问题讨论】:

  • 你在 C++ 领域,完全停止使用 sprintf。您想要动态构建字符串的可能是 std::stringstream
  • "First of all, print the documentation about "safe/unsafe" functions from MSDN and burn it!" - vsnprintf() 已被弃用,不要相信 VS,它是 废话。
  • vsnprintf 很容易被误用,提防并非没有道理。
  • 不幸的是,vsnprintf_s 文档非常不准确。它声明如果缓冲区为空或计数为 0,它将返回 -1 并设置 errno,但这并不完全正确。如果为缓冲区传递 null,为 sizeOfBuffer 传递 0,为计数传递 0,它将返回 0(前提是您没有将 null 作为格式字符串传递),并且不会设置 errno。此外,如果您传递一个实际缓冲区和一个实际大小但计数为 0,它将返回 -1 但不设置 errno。该文档还指出,如果缓冲区为空或计数为 0,则将调用无效的参数处理程序。也不正确。 1/2
  • 我上面描述的工作流都不会调用无效的参数处理程序。文档说明“如果计数 耸耸肩。另外值得注意的是,vsnprintf(不是 _s)的 MSDN 文档指出“如果缓冲区或格式为 NULL,或者如果计数小于或等于零,则这些函数调用无效参数处理程序”。不对。您可以将一个空缓冲区传递给它,它会为您提供所需的长度(减去空终止符)作为返回值。 2/2

标签: c visual-studio-2010 printf


【解决方案1】:

事实证明,这个问题几乎与以下内容完全相同:

Calculating the size of an sprintf() buffer

答案总结:

使用_vscprintf 计算缓冲区应该有多大,然后使用vsnprintf_s 实际填充它。

【讨论】:

    【解决方案2】:

    VC 终于实现了标准vsnprintfSee the ever unreliable MSDN.

    【讨论】:

    • 似乎任何对大 M 的批评都会受到反对票的认可...+1
    • 我从来没有说过vsnprintf 没有实现。它始终被实施,但也被标记为已弃用,并发出C4996 警告。
    • 向微软提交错误报告。 vsnprintf 是一个标准函数,并没有被任何实际权威所弃用。
    • 不是我,但我认为“请参阅永远不可靠的 MSDN”可能已经赢得了反对票。评论。我几乎跳过了过去 10 年左右的时间,但在过去的十年(左右)中,MSDN 曾经是“最可靠的”文档,实际上,如果有记忆的话。不是没有错误,而是更好的错误之一。
    • @Sz。请参阅有关问题的 cmets,指出了一些不准确之处。 MSDN 也充满了 MS 的废话,写得好像它是标准的一样。他们认为他们有一个“更安全”的版本(但直到几年前他们的vsnprintf 甚至不符合 C99)是另一个例子。 MSDN 可能有所改进(我上次看到它是垃圾),但它仍然充满了非标准的东西,几乎没有说明什么是标准的,什么不是(因此不可靠)。
    【解决方案3】:

    正如@abelenky 建议的那样,我不会说这是一个重复的问题。如果您想使用vsnzprintf_s 代替旧的vsnprintf,您需要将_TRUNCATE(扩展为((size_t)-1))作为count 参数(第三个参数)传递。

    https://msdn.microsoft.com/en-us/library/d3xd30zz.aspx

    如果存储数据和终止 null 所需的存储空间超过 sizeOfBuffer,则调用无效的参数处理程序,如参数验证中所述,除非 count 为 _TRUNCATE,在这种情况下,缓冲区中可容纳的字符串数量为写入并返回 -1。如果在无效参数处理程序之后继续执行,这些函数将缓冲区设置为空字符串,将 errno 设置为 ERANGE,并返回 -1。

    【讨论】:

      【解决方案4】:

      要获取缓冲区大小,您可以这样做:

      size_t size = _vscprintf(format, argptr);

      这里有一个很好的概述vsnprintf vs vsnprintf_s。如果缓冲区或格式参数是空指针,则本质上 vsnprintf_s 返回 E_INVAL 错误。如果不为 null,vsnprintf_s 最多写入缓冲区大小,截断超出大小的数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-18
        • 1970-01-01
        • 2016-01-17
        • 2020-03-03
        • 2020-10-08
        相关资源
        最近更新 更多