snprintf()总是null终止?

Pro*_*ica 73 c posix libc

snprintf是否始终为null终止目标缓冲区?

换句话说,这是否足够:

char dst[10];

snprintf(dst, sizeof (dst), "blah %s", somestr);
Run Code Online (Sandbox Code Playgroud)

或者你必须这样做,如果somestr足够长?

char dst[10];

somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);
Run Code Online (Sandbox Code Playgroud)

我对标准所说的以及一些流行的libc可能做的不是标准行为感兴趣.

Mar*_* Ba 67

正如其他答案所确定的那样:它应该:

snprintf...将结果写入字符串缓冲区.除非buf_size为零,否则(...)将以空字符终止.

所以你需要注意的是你没有将零大小的缓冲区传递给它,因为(显然)它不能将"零"写入"无处".


但是,要注意 Microsoft的库没有调用的函数,snprintf但在历史上只有一个函数调用_snprintf(注意前导下划线),它不附加终止空值.这是文档(VS 2012,~~ VS 2013):

http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx

回报价值

设len为格式化数据字符串的长度(不包括终止空值).len和count是_snprintf的字节数,_snwprintf是宽字符.

  • 如果len <count,则len字符存储在缓冲区中,附加null终止符,并返回len.

  • 如果len = count,则len字符存储在缓冲区中,不附加null-terminator,并返回len.

  • 如果len> count,则count字符存储在缓冲区中,不附加空终止符,并返回负值.

(......)

Visual Studio 2015(VC14)显然引入了一致性snprintf函数,但具有前导下划线和 null终止行为的遗留函数仍然存在:

snprintf当len大于或等于count时,该函数通过在null处放置null-terminator来截断输出 buffer[count-1].(......)

所有功能的其它snprintf,如果LEN =计数,len个字符被存储在缓冲器中,没有空终止符被附加,(...)

  • 什么叫Aslan的是微软工程师在介绍`_snprintf`时的想法,它静静地删除了`snprintf`**的关键安全功能,并允许字符串不被空终止?! (20认同)
  • @ColinDBennett - 这很奇怪而且非常讨厌,如果有人想的话我也不知道:-) (2认同)
  • @MartinBa对不起,我测试的是`template <size_t size> int _snprintf_s(char(&buffer)[size],size_t count,const char*format [,argument] ...);`我还应该提到这个只发生/ GS(安全检查)编译标志.该函数知道大小,数量和长度. (2认同)
  • 请注意mingw64将Microsoft _snprintf实现用作(使用?)“正常” snprintf,除非另行指定,否则https://nvd.nist.gov/vuln/detail/CVE-2018-1000101 (2认同)
  • @Sajjon这是一个无可否认的愚蠢(也许完全原创)的愤怒感叹(https://idioms.thefreedictionary.com/in+the+name+of+God)也许有点像一个刻薄的誓言(https://en.wikipedia) .org/wiki/Minced_oath )。另一个例子可能是“以宙斯之名做什么……?!” (https://forum.wordreference.com/threads/in-the-name-of-zeus.2132965/) (2认同)

pio*_*otr 18

根据snprintf(3)手册页.

函数snprintf()vsnprintf()写入最多size字节(包括尾随空字节('\ 0'))str.

所以,是的,如果size> = 1则无需终止.

  • 我知道,但看看strncat()的灾难是一个反例...... (11认同)
  • 感谢上帝; 这是唯一明智的设计.这些函数的检查版本的全部要点是*安全*,如果你不得不手工完成所有终止malarkey,这将是非常糟糕的. (3认同)
  • 我建议在依赖它之前在您正在使用的平台上对其进行测试。即使它应该写入空字节,我也知道我遇到过没有写入空字节的实现(可能是 MinGW,它使用了较旧的 MS 运行时)。 (2认同)
  • 我不相信你引用的这句话实际上意味着你认为的意思。作为以英语为母语的人,这显然意味着只要字符串加上它的空终止符等于或小于大小,它就会全部被写入。但这句话本身绝对不能描述所写的内容,如果篇幅不够写的话。 (2认同)

Jon*_*ler 10

根据C标准,除非缓冲器大小为0,vsnprintf()snprintf()零终止其输出.

snprintf()函数应相当于sprintf(),加上n参数,该参数表示s引用的缓冲区的大小.如果n为零,则不应写入任何内容,并且s可能是空指针.否则,应丢弃超出n-1的输出字节而不是写入数组,并在实际写入数组的字节末尾写入空字节.

因此,如果您需要知道要分配的缓冲区大小,请使用零大小,然后可以使用空指针作为目标.请注意,我链接到POSIX页面,但是这些明确表示标准C和POSIX之间没有任何分歧,它们涵盖相同的基础:

此参考页面上描述的功能与ISO C标准一致.此处描述的要求与ISO C标准之间的任何冲突都是无意的.本卷POSIX.1-2008符合ISO C标准.

警惕微软版本vsnprintf().当缓冲区中没有足够的空间时,它与标准C版本的行为完全不同(它返回-1,标准函数返回所需的长度).微软版本null在错误条件下终止其输出并不完全清楚,而标准C版本则如此.

另请注意您使用TR 24731安全功能的答案吗?(请参阅MSDN的Microsoft版本vsprintf_s())和Mac解决方案,以便安全替代不安全的C标准库函数?


Art*_*Art 5

一些旧版本的 SunOS 对 snprintf 做了一些奇怪的事情,并且可能没有以 NUL 终止输出,并且返回值与其他人所做的不匹配,但是过去 10 年中发布的任何内容都在做 C99 的事情说。