7

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

通过 SUS,对于%n格式字符串,相应的int将设置为 -amount-of-bytes-written-to-the-output。此外,对于snprintf(dest, 3, "abcd")dest将指向"ab\0"。为什么?dest因为要写入输出(缓冲区)的字节数不超过 n (n = 3 )。

我推断出代码:

int written;
char dest[3];
snprintf(dest, 3, "abcde%n", &written);

written将设置为 2(从计数中排除空终止)。但是从我使用 GCC 4.8.1 进行的测试中,written设置为 5。我是否误解了标准?它是一个错误吗?它是未定义的行为吗?

编辑:

@wildplasser 说:

...格式字符串中 %n 的行为可能未定义或实现已定义...

...实现必须模拟处理完整的格式字符串(包括 %n)...

@par 说:

written%n是 5,因为这是在遇到 时将写入的字符数。这是正确的行为。 snprintf最多只复制size字符减去尾随的 null ...

和:

另一种看待这个问题的方法是,%n如果它只处理最多 2 个字符,甚至都不会遇到,所以可以想象written会有一个无效的值......

和:

...整个字符串通过printf()规则处理,然后应用最大长度...

它可以被验证为标准、标准草案或一些官方来源吗?

4

2 回答 2

7

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

另一种看待这个问题的方法是,%n如果它只处理最多 2 个字符,甚至都不会遇到,因此可以预期written会有一个无效值。written如果您期望在该点%n遇到有效的东西(但没有),那就会出现错误。

所以请记住,整个字符串是通过printf()规则处理的,然后应用最大长度。

于 2014-08-28T19:12:20.423 回答
5

这不是错误:ISOC99 说

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

所以它只是丢弃尾随输出,但在其他方面表现相同。

于 2014-08-28T19:15:01.477 回答