最近,我注意到了一个我想要验证的奇怪案例:
通过SUS,对于格式字符串中的%n
,相应的int
将被设置为写入到输出的字节量。
此外,对于snprintf(dest, 3, "abcd")
,dest
将指向"ab\0"
。为什么?因为要将不超过n(n = 3)个字节写入输出(dest
缓冲区)。
我推断出代码:
int written;
char dest[3];
snprintf(dest, 3, "abcde%n", &written);
written
将设置为2(从计数中排除空终止)。
但是根据我使用GCC 4.8.1进行的测试,written
设置为5。
我是否误解了标准?这是一个错误吗?是不确定的行为?
编辑:
@wildplasser说:
...格式字符串中%n的行为可能是未定义的或实现定义的......
和
...实现必须模拟处理完整的格式字符串(包括%n)...
@par说:
written
为5,因为在遇到%n
时会写入多少个字符。这是正确的行为。snprintf
仅复制size
个字符减去尾随空值...
和
另一种看待这种情况的方法是,
%n
如果最多只处理2个字符就不会遇到written
,因此可以想到printf()
价值无效......
和
...整个字符串通过{{1}}规则处理,然后应用最大长度......
可以通过标准,标准草案或某些官方来源进行验证吗?
答案 0 :(得分:7)
written
是5,因为这是在遇到%n
时写入的字符数。这是正确的行为。 snprintf
只复制最多size
个字符减去尾随空值(因此在您的情况下3-1 == 2.您必须将字符串格式化行为与仅写入这么多的字符分开。
另一种看待这种情况的方法是,如果%n
仅处理最多2个字符,则甚至不会遇到written
,因此可以预期written
会产生无效值。如果您在%n
遇到printf()
时遇到有效的东西(并且没有),那就是存在错误的地方。
请记住,整个字符串是通过{{1}}规则处理的,然后应用了最大长度。
答案 1 :(得分:5)
这不是一个错误:ISOC99说
snprintf函数等同于fprintf [...] 超出n-1的输出字符将被丢弃而不是写入数组 [...]
所以它只是丢弃尾随输出,但行为相同。