到目前为止在snprintf中写的字符

时间:2014-08-28 18:58:59

标签: c gcc c99 format-string

最近,我注意到了一个我想要验证的奇怪案例:

通过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}}规则处理,然后应用最大长度......

可以通过标准,标准草案或某些官方来源进行验证吗?

2 个答案:

答案 0 :(得分:7)

written是5,因为这是在遇到%n时写入的字符数。这是正确的行为。 snprintf只复制最多size个字符减去尾随空值(因此在您的情况下3-1 == 2.您必须将字符串格式化行为与仅写入这么多的字符分开。

另一种看待这种情况的方法是,如果%n仅处理最多2个字符,则甚至不会遇到written,因此可以预期written会产生无效值。如果您在%n遇到printf()时遇到有效的东西(并且没有),那就是存在错误的地方。

请记住,整个字符串是通过{{1}}规则处理的,然后应用了最大长度。

答案 1 :(得分:5)

这不是一个错误:ISOC99说

  

snprintf函数等同于fprintf   [...]   超出n-1的输出字符将被丢弃而不是写入数组   [...]

所以它只是丢弃尾随输出,但行为相同。