Apple developer documentation州:
fgets
的安全说明:尽管fgets
功能提供了读取有限数量数据的功能,但在使用时必须小心。与“更安全”列中的其他函数一样,fgets
始终终止字符串。但是,与该列中的其他函数不同,它需要读取最大字节数,而不是缓冲区大小。
最后一句话对我来说听起来不对。为了比较,这里是what POSIX says:
fgets()
函数应从流中读取字节到s
指向的数组,直到读取n-1
个字节,或者读取<newline>
并将其传输到{{ 1}},或遇到文件结束条件。在读入数组的最后一个字节后,应立即写入空字节。
以下是an ISO C draft from 2005 says:
s
函数从fgets
指向的流中将n
指定的字符数最多读取一个小于stream
指向的数组。在换行符(保留)或文件结束后不会读取其他字符。在读入数组的最后一个字符后立即写入空字符。
FreeBSD手册页与C标准和POSIX相同。
这让我觉得Apple文档显然是错误的。最简单的解释是,Apple发表这篇文章时并不知道。但是虽然很简单,但这个假设对我来说并不合理。
还有其他原因导致Apple可能偏离C标准的措辞吗?
答案 0 :(得分:2)
甚至早期(20世纪70年代早期)fgets()
版本指定n
是缓冲区大小,缓冲区将以'\0'
终止。
Kernighan和Ritchie在他们的所有书籍和文档中都正确地反映了这一点。
然而,许多介绍性文章的作者(我不会尝试命名,因为我确定我会错过一些,并且所有人都应该同样感到尴尬)记录了这一点。可以将n
个字符写入缓冲区,并且在某些情况下可能会删除尾随的'\0'
。
答案 1 :(得分:1)
fgets
函数最多读取大小减去文件中的一个字节。如果错误的值作为缓冲区大小传递,则fgets
可能会写出越界。
因此,您显示的Apple文档中的引用是正确的,因为该值与从文件中读取的字节数更相关。但另一方面,任何普通代码在下降fgets
时都会使用实际的缓冲区大小。如果该数字是从用户输入的,则应在使用前进行验证。
另一方面,文件继续说明(感谢Sander De Dycker的说明)
实际上,这意味着您必须始终传递一个小于缓冲区大小的大小值,以便为空终止留出空间。如果不这样做,
fgets
函数将尽可能地终止缓冲区末尾的字符串,可能会覆盖其后的任何字节数据。
这个是错误的。传递给fgets
的size参数始终包含字符串终止符。至少根据C标准。