【问题标题】:Why does fgets accept an int instead of a size_t?为什么 fgets 接受 int 而不是 size_t?
【发布时间】:2016-08-02 11:53:43
【问题描述】:

strcpy()malloc()strlen() 和其他各种函数接受它们的参数或返回值作为 size_t 而不是 intunsigned int,原因很明显。

fread()fwrite() 等一些文件函数也使用size_t。通过扩展,预计char* fgets (char *str, int num, FILE *stream) 应该使用size_t 而不是int 作为其缓冲区大小的参数。

但是,fgets() 使用 int。有没有客观的解释原因?

【问题讨论】:

  • C 标准库中没有一致性。功能随着时间的推移而发展。 size_t 在引入fgets 时可能不存在(只是我的猜测)。
  • 看到这样的问题得到如此高的投票总是很茫然。我同意@P.P.:这是OT。
  • @user2064000 如果不太可能有任何真正的理由和引用——就像这里的情况——那么人们只会根据自己的想象力疯狂猜测,这让我们无处可去。这并不一定意味着您被暗示要求,但这可能是现实问题的结果。
  • 这不是意见导向的:K&R 在第 155 页定义了 fgets() 并带有 int 参数。他们的代码也可以使用unsigned intsize_t 后来在 C89 (ANSI C) 中作为 sizeof() 的类型引入。因此更新了内存管理功能。但文件 I/O 不是:唯一使用 size_t 的文件函数是 C89 引入的,在 K&R 中不存在(例如:fread()/fwrite():K&R 仅在文件描述符上使用 unix 读/写对于 bloc 操作,当时没有 fread/fwrite )

标签: c language-lawyer size-t


【解决方案1】:

最初的 K&R 在第 155 页定义了 fgets(),并带有 int 参数。书中介绍的代码本来可以工作的 也有unsigned int(它使用>0,但循环的编写是为了永远不会低于零)。

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

需要注意的是,协调unix功能的POSIX standard是与 ANSI C 标准和issued late 1988。该标准协调了许多 unix 函数以使用 size_t,因此如今 read()/write()size_t 定义。但是对于fgets()等C标准库函数,POSIX优先于C标准 (当前版本标准的措辞):

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

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


编辑:补充阅读

stdio.h: 这个头文件定义了 K&R 的第 7 章中列出的大部分函数并对其进行原型化。很少,如果有的话,在 在 K&R 中找到了定义,但添加了几个新功能。

【讨论】:

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