问题 为什么fgets接受int而不是size_t?


功能如 strcpy()malloc()strlen() 和其他人接受他们的论点或返回值作为 size_t 代替 int 或者 unsigned int 原因很明显。

一些文件功能如 fread() 和 fwrite() 使用 size_t 同样。通过扩展,可以预期 char* fgets (char *str, int num, FILE *stream) 应该用一个 size_t 而不是 int 作为其缓冲区大小的参数。

然而, fgets() 用一个 int。有客观解释为什么?


10887
2017-08-02 11:53


起源

C标准库没有一致性。功能随着时间的推移而发展。 size_t 可能不存在的时候 fgets 介绍了(只是我猜)。 - user694733
歇斯底里的葡萄干。可能是(标准化之前)的早期实施恰好使用 int 当C标准化时,它继续用于“兼容性”。我投票结束了 意见为主。 - P.P.
总是茫然看到这样的问题如此受欢迎。我同意@ P.P:这是OT。 - LPs
@ user2064000如果不太可能有任何真正的理由和引用 - 就像在这里似乎就是这样 - 那么人们就会根据自己的想象疯狂猜测,这让我们无处可去。这并不一定意味着你被暗示为 要求 那,但这可能是现实问题的结果。 - underscore_d
这不是意见导向:K&R定义 fgets() 在第155页上 int 论据。他们的代码可以使用 unsigned int 同样。 size_t 稍后介绍,在C89(ANSI C)中作为类型 sizeof()。因此更新了内存管理功能。但文件I / O不是:唯一使用的文件函数 size_t是由C89引入的并且在K&R中不存在(例如:fread()/ fwrite():K&R在文件描述符上仅使用unix读/写进行块操作,当时没有fread / fwrite) - Christophe


答案:


最初的K&R定义 fgets() 在第155页上 int 论据。书中提供的代码可行 与 unsigned int 同样(它使用了一个 >0,但循环被写入,以便永远不会低于零)。

size_t 后来介绍了 C89 (ANSI C),作为类型 sizeof()。由于此功能专门用于协调内存分配,内存 管理功能和字符串功能相应更新。但文件I / O不是:唯一使用的文件函数 size_t 在C89中是那些新的 由C89引入并且例如在K&R中不存在 fread()/fwrite()。是的,K&R没有这些功能 并且仅依赖于使用文件描述符的(非可移植)unix读/写函数的bloc操作。

应该指出的是 POSIX标准,协调了unix功能,与...并行开发 ANSI C标准和 1988年末发行。该标准已经统一了许多unix函数 size_t 以便 read()/write() 如今 定义为 size_t。但对于C标准库等功能 fgets(),POSIX优先于C标准 (当前版本标准的措辞):

此参考页面上描述的功能与ISO C标准一致。   此处描述的要求与ISO C标准之间的任何冲突都是无意的。

所以在POSIX中,具有讽刺意味的是, fgets() 仍然继承了历史悠久的K&R int


编辑:额外阅读

stdio.h中:  该标题定义并原型化了K&R第7章中列出的大多数功能。很少,如果有的话,改变了   在K&R中找到了定义,但增加了几个新功能。


9
2017-08-02 15:23



您是否知道任何值得注意的C89前F89实现在传递负值时是否可预测[例如可以预见地将它视为零,可以预测无所事事,读取-N字节数据但省略换行符等等。如果是这样,更改为size_t可能会禁止实现支持该功能,除非长度限制为SIZE_T_MAX-UINT_MAX [从我所知道的,传递大于缓冲区大小的长度定义的行为提供了一个新行成功读取的结束之前缓冲区]。 - supercat
K&R的实现可以追溯到1978年。因为它是有符号整数,第一个循环条件是 --n>0 它会停止并将null终止符放在缓冲区中。如此完全可以预测。如果参数是无符号的,则相同的代码可能会产生缓冲区溢出,但会在最大UINT_MAX迭代后停止(除非硬件会捕获符号位的翻转)。然后也可能有其他实现:pre 89有很多编译器制造商,其中大部分现在已不再为人所知;-)。 - Christophe
@supercat我可以找回1986年我以前的Lattice C编译器(被微软收购)与其标准库的来源。 fgets() 是用。实现的 for(i=0; i<n-1; ) 这也将为负数返回一个空字符串。并且它也可以与无符号参数完美配合。 - Christophe
如果该值大于缓冲区的大小,但是在缓冲区溢出之前收到换行符,是否会将行为定义为将数据读取到换行符?如果,那么,那将意味着,如果 size 被改为了 size_t, 然后 fgets(buff, -1, file) 会有一个 定义 行为与预先存在的行为不同。标准的作者不反对将在不同实现中以各种方式定义的事物标记为未定义行为,因为他们认为不会阻止任何人继续支持...... - supercat
......已经在使用的有用行为[这种期望在整个二十世纪都存在,但后来受到了攻击],但不愿意定义任何实现可能以相反方式定义的行为。 - supercat