C 迄今为止使用snprintf编写的字符
最近,我注意到一个奇怪的案例,我想核实一下: 根据SUS,对于格式字符串中的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
%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()
分配的缓冲区,但它发生在幕后。@也许您会这样做……关心堆栈溢出的实现者不会这样做