【问题标题】:Is the output of snprintf guaranteed to be null-terminated with Visual Studio 2015?snprintf 的输出是否保证在 Visual Studio 2015 中以空值终止?
【发布时间】:2016-01-20 22:48:52
【问题描述】:

我正在使用我的前任使用的 C 代码库:

#ifdef _MSC_VER
  // Map to equivalent function
  #define snprintf sprintf_s
#endif

代码库需要在 Linux (gcc/clang)、OSX (gcc/clang) 和 Windows (VS) 上编译。我第一次尝试在 Visual Studio 2015 中编译代码。以前使用过 Visual Studio 2010。我遇到了here 描述的错误,并且能够使用已接受答案中的线索进行编译:

#ifdef _MSC_VER
  #if _MSC_VER<1900
    #define snprintf sprintf_s
  #endif
#endif

该项目现在可以使用 Visual Studio 2015 编译并在 OSX 上运行。但是,我担心sprintf_s 文档中的一个声明:

与 snprintf 不同,sprintf_s 保证缓冲区将以空值结尾(除非缓冲区大小为零)。

如果 Visual Studio 包含符合 C99 的 snprintf 版本,是否不应该保证缓冲区以空值终止?

我写了一个小程序来评估行为。

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    char buf[5];
    snprintf(buf, sizeof(buf), "abcdef");
    printf("buffer: %s\n", buf);
    printf("size of buffer: %lu\n", strlen(buf));
    printf("last character a null terminator?: %s\n",
        (strcmp(&buf[4], "\0") == 0) ? "yes" : "no");
    return 0;
}

我在 OSX 和 Windows 上使用 Visual Studio 2015 构建并运行了该程序。

在 OSX 上,输出为:

~$c99 main.c
~$./a.out 
buffer: abcd
size of buffer: 4
last character a null terminator?: yes

在带有 Visual Studio 2015 的 Windows 7 上,输出为

> printf_evaluation.exe
buffer: abcd
size of buffer: 4
last character a null terminator?: yes

这不是表明输出实际上是空终止的,并表明 MSDN 文档不正确吗?我的例子是不是太琐碎了?是否存在 snprintf 的输出可能不会在 Visual Studio 2015 中以 NULL 终止的情况?

【问题讨论】:

  • 我认为,他们的意思是 与 _snprintf 不同,它确实不会以空值终止。 VS 根本不知道 snprintf(除了作为 sprintf_s 的宏)
  • 我怀疑这是一个文档错误,而不是在 Visual Studio 中实现 snprintf() 的任何异常/错误。
  • 微软 1980 年代实现的 snprintf 与 C99 标准不同;这是所有这些问题的根源。 IDK 何时(如果有的话)VS 运行时已更新为使用 C99 版本。
  • MS 从未努力遵守 C99 - 是什么让您认为“Visual Studio 包含符合 C99 的 snprintf 版本”?
  • 建议,用于验证实际发生的情况....编写一个小程序,将“超长”缓冲区传递给 snprintf(),然后使用调试器查看实际放置在结果缓冲区中的内容。

标签: c visual-studio-2015 c99


【解决方案1】:

snprintf() 总是 nul 终止缓冲区,只要它的第二个参数大于零。所以是的,MSDN 文档是错误的。

From C11 standard, snprintf():

snprintf 函数等价于 fprintf,除了输出 被写入一个数组(由参数 s 指定)而不是 溪流。 如果 n 为零,则不写入任何内容,并且 s 可能为 null 指针。否则,第 n-1 个以外的输出字符是 被丢弃而不是被写入数组,并且 一个空字符 写在实际写入的字符的末尾 如果复制发生在重叠的对象之间,则 行为未定义。

(强调我的)。

【讨论】:

  • MSDN 文档将描述 MS 工具的行为,这可能与 ISO C 标准不同。 AFAIK,MS 从未声称支持 C99(更不用说 C11)
  • this blog:snprintf 和 vsnprintf 现已实现:C99 snprintf 和 vsnprintf 函数已实现。
  • 我用 MSVC 9.0 和 15.0 运行了这个例子。前一个没有snprintf,只有_snprintf,使用后者,两个编译器都生成了将5个字符写入字符串并且没有终止它的代码。然而,MSVC 15.0 确实有 snprintf,其行为与 OP 所说的一样。 _snprintf 的 MSVC 文档说 “此函数不保证 NULL 终止”,并且该组文档未提及 snprintf。所以是的,存在文档错误,snprintf_snprintf 两个版本的行为不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 2016-10-01
  • 1970-01-01
  • 2015-07-30
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多