歧义始于C标准本身。 C99和C11都具有相同的snprintf函数描述。以下是来自C99的描述:
7.19.6.5 snprintf函数
概要
1 #include
int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
描述
2 snprintf函数等效于fprintf,不同之处在于输出写入数组(由参数s指定),而不是流。如果n为零,则不会写入任何内容,并且s可以是空指针。否则,超出第n-1个字符的输出将被丢弃,而不是写入数组,并且在实际写入数组的字符末尾写入空字符。如果在重叠对象之间进行复制,则行为未定义。
返回值
3 snprintf函数返回将写入的字符数(不包括终止的空字符),如果发生编码错误,则返回负值。因此,当且仅当返回值为非负且小于n时,已完全写入以空字符结尾的输出。
一方面,以下语句
“否则,超出第n-1个字符的输出将被丢弃,并在实际写入数组的字符末尾写入空字符”
表示,如果(s指向一个长度为3的数组并且)n为3,则将写入2个字符,并且第2个字符之后的字符将被丢弃;然后,在这些字符之后写入空字符(空字符将是第3个写入的字符)。
我相信这回答了原始问题。
答案:
如果在重叠对象之间进行复制,则行为未定义。
如果n为0,则不会将任何内容写入输出;
否则,如果没有遇到编码错误,则输出始终以空字符结尾(无论输出是否适合输出数组;如果不适合,则丢弃一些字符,以使输出数组永远不会溢出);
否则(如果遇到编码错误),输出可能保持非以空字符结尾的状态。
另一方面,最后一句话
因此,仅当返回的值为非负且小于
n
时,空字符结尾的输出才已完全写入。这句话存在歧义(或者说是我的英语不够好)。我可以用至少两种方式来解释这个句子:
1. 当且仅当返回的值为非负且小于
n
时,输出才
以空字符结尾(这意味着如果返回的值
不小于
n
,即输出(包括终止的空字符)无法适应数组大小,则输出
没有以空字符结尾)。
2. 当且仅当返回的值为非负且小于
n
时,输出
完整(没有任何字符被丢弃)。
我认为上述解释1与答案相矛盾,会导致误解和冗长的讨论。这就是为什么最后一个描述
snprintf
函数的句子需要更改,以消除任何歧义(从而提出向C语言标准提案的理由)。
我认为可以从
http://en.cppreference.com/w/c/io/fprintf中采用无歧义措辞的例子(请参见
4
),感谢 @"Martin Ba" 提供的链接。
另请参见问题“
snprintf:是否有C标准提案/计划更改此函数的描述?”。