C 迄今为止使用snprintf编写的字符

C 迄今为止使用snprintf编写的字符,c,gcc,c99,format-string,C,Gcc,C99,Format String,最近,我注意到一个奇怪的案例,我想核实一下: 根据SUS,对于格式字符串中的%n,相应的int将设置为写入输出的字节数。 此外,对于snprintf(dest,3,“abcd”),dest将指向“ab\0”。为什么?因为写入输出(dest缓冲区)的字节数不超过n(n=3) 我推断,对于代码: int written; char dest[3]; snprintf(dest, 3, "abcde%n", &written); write将设置为2(计数中不包括空终止)。 但根据我使用GC

最近,我注意到一个奇怪的案例,我想核实一下:

根据SUS,对于格式字符串中的
%n
,相应的
int
将设置为写入输出的字节数。 此外,对于
snprintf(dest,3,“abcd”)
dest
将指向
“ab\0”
。为什么?因为写入输出(dest缓冲区)的字节数不超过n(n=3)

我推断,对于代码:

int written;
char dest[3];
snprintf(dest, 3, "abcde%n", &written);
write
将设置为2(计数中不包括空终止)。 但根据我使用GCC4.8.1进行的测试,
write
被设置为5。 我是否误解了标准?是虫子吗?这是未定义的行为吗

编辑:

@wildplasser说:

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

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

@帕尔说:


writed
为5,因为这是在遇到
%n
时要写入的字符数。这是正确的行为
snprintf
最多只能复制
size
个字符减去尾部的null

以及:

另一种方法是,如果
%n
最多只处理2个字符,则根本不会遇到它,因此可以想象
write
会有一个无效值

以及:

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


是否可以验证它是标准、标准草案或某些官方来源?

写入的
为5,因为这是在遇到
%n
时写入的字符数。这是正确的行为
snprintf
最多只能复制
size
个字符减去尾随的null(因此在您的示例中,3-1==2。您必须将字符串格式行为与只写入这么多字符分开

另一种方法是,如果
%n
最多只处理2个字符,则根本不会遇到它,因此可以想象
%n
编写的
会有一个无效值。如果在
%n
被编码时,您希望
编写的
中有有效的内容,那么就会出现错误他被打断了(但没有)


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

这不是一个bug:ISOC99说

snprintf函数相当于fprintf [...] 超过n-1st的输出字符将被丢弃,而不是写入数组 [……]


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

在我看来像是一个bug(在库实现中)。我希望您应该首先查看snprintf()中的返回值。“副作用”不同;如果返回值>=第二个参数,则格式字符串中
%n
的行为可能未定义或实现已定义。在任何情况下,实现必须模拟处理完整的格式字符串(包括
%n
)为了获得正确的返回值,因此可以动态获得副作用。嗯,标准文本包含“…到目前为止写入输出流的字符数…”;
'c'
'd'
'e'
未写入输出stream@pmg-字符被写入输出流,只要输出流是printf()函数中“幕后”的数据缓冲区。然后,snprintf只从“输出流”复制最大大小的字符的行为发生。请参阅Heinz的答案以获取对ISOC99的引用。然后,可能引用
%n“
的文本不适用于
sprintf()
,因为此函数不写入输出流。请考虑如何实现
snprintf()
:调用
vasprintf()
,然后调用
memcpy()
,然后调用
free()
。在这里,您可以清楚地看到输出流是由
vasprintf()
分配的缓冲区,但它发生在幕后。@也许您会这样做……关心堆栈溢出的实现者不会这样做