snprintf是否始终为空以终止目标缓冲区?
换句话说,这是否足够:
char dst[10];
snprintf(dst, sizeof (dst), "blah %s", somestr);
或者你必须这样做,如果一些字符串足够长?
char dst[10];
somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);
我感兴趣的是标准说了什么,以及一些流行的libc可能会做什么,这不是标准的行为。
5条答案
按热度按时间tp5buhyn1#
正如其他答案所表明的:它should:
snprintf
...将结果写入字符串缓冲区。(...)将以空字符终止,除非buf_size为零。因此,您需要注意的是,不要将大小为零的缓冲区传递给它,因为(很明显)它不能将零写入“nowhere”。
然而,请注意微软的库 * 没有 * 一个名为
snprintf
的函数,而是历史上 * 只有 * 一个名为_snprintf
的函数(注意前导下划线),该函数 * 不追加 * 终止空值。以下是文档(VS 2012,~~ VS 2013):http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx
传回值
设len为格式化数据字符串的长度(不包括终止空值)。_snprintf的len和count以字节为单位,_snwprintf的len和count以宽字符为单位。
(...)
Visual Studio 2015(VC 14)显然引入了一致的
snprintf
函数,但是仍然存在带有前导下划线和 * 非 * 空终止行为的旧函数:**
snprintf
**函数通过在buffer[count-1]
处放置空终止符,在len大于或等于count时截断输出。(...)对于除
snprintf
之外的所有函数,如果len = count,则len字符存储在缓冲区中,* 不追加空终止符 *,(...)eulz3vhy2#
根据snprintf(3)联机帮助页。
函数
snprintf()
和vsnprintf()
最多将size
字节(包括尾随空字节('\0'))写入str
。所以,是的,如果size〉= 1,就不需要终止。
bweufnob3#
根据C标准,除非缓冲区大小为0,否则
vsnprintf()
和snprintf()
null终止其输出。snprintf()
函数应等同于sprintf()
,但增加了n参数,该参数说明s引用的缓冲区大小。如果n为零,则不写入任何内容,并且s可以是空指针。否则,应丢弃第n-1个以外的输出字节,而不是将其写入数组。并且在实际写入阵列的字节的末尾写入空字节。因此,如果你需要知道要分配多大的缓冲区,那么就使用大小为零的缓冲区,然后你可以使用一个空指针作为目的地。注意,我链接到了POSIX页面,但是这些页面明确地表明,在标准C和POSIX之间没有任何分歧,因为它们涵盖了相同的领域:
本参考页中描述的功能符合ISO C标准。此处描述的要求与ISO C标准之间的任何冲突都是无意的。本卷POSIX.1-2008遵循ISO C标准。
请注意Microsoft版本的
vsnprintf()
。当缓冲区中没有足够的空间时,它的行为肯定与标准C版本不同(它返回-1,而标准函数返回所需的长度)。Microsoft版本的null在错误条件下终止其输出,而标准C版本在错误条件下终止其输出,这一点并不完全清楚。但是,请注意,自最初编写此答案以来,Microsoft已更改了规则(
vsnprintf()
):从Visual Studio 2015和Windows 10中的UCRT开始,
vsnprintf
不再等同于_vsnprintf
。vsnprintf
函数符合C99标准;保留_vnsprintf
是为了与旧版Visual Studio程式码回溯相容。类似的注解适用于
snprintf()
和sprintf()
。另请注意Do you use the TR 24731 safe functions?(有关
vsprintf_s()
的Microsoft版本,请参见MSDN)和Mac solution for the safe alternatives to unsafe C standard library functions?的答案dfty9e194#
一些旧版本的SunOS使用snprintf做了一些奇怪的事情,可能没有以NULL终止输出,并且返回值与其他人所做的不匹配,但是在过去10年中发布的任何东西都在做C99所说的事情。
omjgkv6w5#
C标准本身就有歧义。C99和C11对
snprintf
函数的描述完全相同。以下是C99的描述:7.19.6.5
snprintf
函数概要
1个1 m2n1x
说明
2
snprintf
函数等效于fprintf
,不同之处在于输出被写入数组(由参数s
指定)而不是流。如果n
为零,则不写入任何内容,并且s
可能是空指针。否则,将丢弃n-1
st以外的输出字符,而不是将其写入数组,并且在实际写入数组的字符的末尾写入一个空字符。如果复制发生在重叠的对象之间,则该行为未定义。退货
3如果
n
足够大,snprintf
函数会返回已经写入的字符数,不计算终止的空字符,如果发生编码错误,则返回负值。因此,当且仅当返回值为非负值且小于n
时,空终止的输出才被完全写入。"一方面“
否则,超出
n-1
st的输出字符将被丢弃,而不是写入数组,并在实际写入数组的字符的末尾写入空字符说
s
指向一个3个字符长的数组,并且)n
为3,则写入2个字符,并丢弃第二个字符以外的字符;则在这2个之后写入空字符(并且空字符将是写入的第三个字符)*。我相信这回答了最初的问题。
答案:
如果在重叠的对象之间进行复制,则该行为未定义。
如果
n
为0,则不向输出写入任何内容否则,如果没有遇到编码错误,* 则输出总是以空结尾 ( 不管输出是否适合输出数组 *;如果不是,则丢弃一些字符以使得输出阵列从不溢出),
否则(如果遇到编码错误),输出 * 可以保持非空终止 *。
"另一方面"
最后一句
因此,当且仅当返回值为非负且小于
n
时,以空值终止的输出才被完全写入给人 * 歧义 *(或者我的英语不够好)。我至少可以从两个方面来解释这个句子:
1.当且仅当返回值为非负且小于
n
时,输出为空终止(这意味着如果返回值 * 不 * 小于n
,即输出(包括终止空字符)不适合数组,则输出 * 不是空终止 *)。2.当且仅当返回值为非负且小于
n
时,输出为complete(未丢弃任何字符)。我认为上面的解释1与答案相矛盾,会引起误解和冗长的讨论。这就是为什么描述
snprintf
函数的最后一句需要修改,以消除任何歧义(这为编写C语言标准建议提供了依据)。我认为,明确措辞的例子可以从http://en.cppreference.com/w/c/io/fprintf(参见
4)
)中得到,这要感谢@“Martin Ba”提供的链接。另请参见问题“snprintf: Are there any C Standard Proposals/plans to change the description of this func?“。