snprintf是否始终为null,终止目标缓冲区?
换句话说,这是否足够:
char dst[10];
snprintf(dst, sizeof (dst), "blah %s", somestr);
或者你必须这样做,如果somestr足够长吗?
char dst[10];
somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);
我对标准所说的内容以及一些流行的libc可能做的不是标准行为感兴趣。
答案 0 :(得分:62)
其他答案确定:should:
snprintf
...将结果写入字符串缓冲区。 (......) 将以null字符终止,除非buf_size为零。
所以你需要注意的是你不会向它传递一个零大小的缓冲区,因为(很明显)它不能写一个零到#34;无处不在"。
但是,要小心,Microsoft的库 没有一个名为历史记录只有有一个名为snprintf
的函数,而是_snprintf
的函数(注意前导下划线),其中不附加终止空值。这是文档(VS 2012,~~ VS 2013):
http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx
返回值
设len为格式化数据字符串的长度(不包括 终止null)。 len和count是_snprintf的宽字节数 _snwprintf的字符。
如果len< count,然后len个字符存储在缓冲区中,a 附加null-terminator,并返回len。
如果len = count,则len个字符存储在缓冲区中, no 附加null-terminator,并返回len。
如果len> count,则count字符存储在缓冲区中, no 附加null-terminator,并返回负值。
(...)
Visual Studio 2015(VC14)显然引入了符合snprintf
函数,但具有前导下划线和非空终止行为的遗留函数仍然存在:
当len更大时,
snprintf
函数会截断输出 通过在null处放置一个null-terminator来计数buffer[count-1]
。 (...)对于所有函数其他而不是
snprintf
,如果len = count,len 字符存储在缓冲区中,没有附加空终结符, (...)
答案 1 :(得分:16)
根据snprintf(3)手册页。
函数
snprintf()
和vsnprintf()
最多将size
个字节(包括尾随空字节('\ 0'))写入str
。
所以,是的,如果尺寸> = 1,则无需终止。
答案 2 :(得分:10)
根据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标准。
警惕微软版vsnprintf()
。当缓冲区中没有足够的空间时,它与标准C版本的行为完全不同(它返回-1,标准函数返回所需的长度)。目前尚不完全清楚Microsoft版本null在错误条件下终止其输出,而标准C版本则终止。
还请注意Do you use the TR 24731 safe functions?的答案(有关vsprintf_s()
的Microsoft版本的MSDN)和Mac solution for the safe alternatives to unsafe C standard library functions?
答案 3 :(得分:4)
某些旧版本的SunOS使用snprintf做了一些奇怪的事情,并且可能没有NUL终止输出并且返回值与其他人正在做的事情不匹配,但过去10年中发布的任何内容都是做C99所说的。
答案 4 :(得分:4)
模糊性从C标准本身开始。 C99和C11都具有相同的snprintf
功能描述。以下是C99的描述:
7.19.6.5
snprintf
功能
的概要强>
1#include <stdio.h> int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
的描述强>
2snprintf
函数等效于fprintf
,但输出被写入数组(由参数s
指定)而不是流。如果n
为零,则不写入任何内容,s
可能是空指针。否则,输出超出n-1
st的字符 丢弃而不是写入数组,并在实际写入数组的字符末尾写入空字符。如果在重叠的对象之间进行复制,则行为未定义 的返回强>
3snprintf
函数返回在n
足够大的情况下写入的字符数,不计算终止空字符,如果发生编码错误则返回负值。因此,当且仅当返回值为非负且小于n
时,才会完全写入以null结尾的输出。
一方面句子
否则,超出
n-1
st的输出字符将被丢弃而不是写入数组,并且在实际写入的字符末尾写入空字符< / strong>进入数组
说
if(s
指向3个字符长的数组,并且)n
为3,则将写入2个字符,并丢弃第2个字符以外的字符强>;然后 null字符写在那些之后(并且空字符将是第3个字符写入)。
我认为这回答了原来的问题
答案:
如果在重叠的对象之间进行复制,则行为未定义
如果n
为0,则不会向输出写入任何内容
否则,如果没有遇到编码错误,输出总是以空值终止(,无论输出是否适合输出数组;如果没有,则丢弃一些字符这样输出数组永远不会溢出),
否则(如果遇到编码错误)输出可以保持非空终止。
另一方面
最后一句
因此,当且仅当返回值为非负且小于
时,才会完全写入以null结尾的输出n
给出歧义(或者我的英语不够好)。我可以用至少两种方式解释这句话:
1.当且仅当返回的值为非负且小于n
时,输出以null结尾(这意味着如果返回的值为 > 小于n
,即输出(包括终止空字符)不适合数组,则输出不是以空值终止)。 />
2.当且仅当返回的值为非负且小于n
时,输出完成(没有丢弃任何字符)。
我认为上述解释与答案相矛盾,引起误解和冗长的讨论。这就是为什么描述snprintf
函数的最后一句需要改变才能消除任何歧义(这为将提案写入C语言标准提供了理由)。
我认为可以从http://en.cppreference.com/w/c/io/fprintf(见4)
)获取非模糊措辞的例子,感谢@&#34; Martin Ba&#34;为链接。
另请参阅问题&#34; snprintf: Are there any C Standard Proposals/plans to change the description of this func?&#34;。