【问题标题】:Ambiguous fread()/fwrite() documentation模棱两可的 fread()/fwrite() 文档
【发布时间】:2021-04-30 19:00:43
【问题描述】:

在 RTFM 之后,我现在有点不清楚如果返回值小于请求元素的数量,我可以从 fread()/fwrite() 的返回值中真正推断出什么。

首先考虑

nhave = fread(dst, 1, nwant, fp);

来自 C17 标准 (7.21.8.1/3):

fread 函数返回成功读取的元素数,如果遇到读取错误或文件结尾,可能小于 nwant

因此,如果 nhave 可能出现读取错误或 eof(但也可能有其他原因)。因为它是 if 而不是 only if,所以在这种情况下,如果 !ferror(fp) ,则无法得出 feof(fp) 的结论。如果!ferror(fp),根据标准,它仍然可以成功读取(nhave 字节)。

MSDNcppreference.com 的措辞相同。

然后POSIX.1-2017:

成功完成后,仅当遇到读取错误或文件结尾时,fread() 才会返回成功读取的小于 nwant 的元素数。

因此,如果 nhave 必须出现读取错误或 eof(不可能有其他原因)。因此在这种情况下,如果!ferror(fp),则可以得出feof(fp)。虽然与 C 标准中的规范不同,但此行为并未标记为 POSIX 中 C 标准的扩展。

并且来自 Linux(符合 POSIX 的平台)上的 fread(3) 手册页:

如果发生错误,或者到达文件末尾,则返回值是一个短项计数(或零)。

正式地说,这是与 POSIX 相反的 (!) 语句。

现在考虑 fwrite(),

nhave = fwrite(src, 1, nwant, fp);

让我们从POSIX.1-2017 开始:

fwrite()函数返回成功写入的元素个数,如果遇到写入错误,可能小于nwant

因此,如果 nhave 可能(但不必)出现写入错误。在这种情况下无法得出结论ferror(fp),但需要检查。

MSDNcppreference.com 的措辞相同。

但是,根据 C17 标准 (7.21.8.2/3),可以得出更多结论:

fwrite函数返回成功写入的元素个数,只有遇到写入错误才会小于nwant

因此在这种情况下,nhave ferror(fp)。

这比上面的 fread() 更奇怪,因为 POSIX、Windows 和 C++ 都应该遵循 C 标准。

那么,这里发生了什么?只是草率的措辞?特别是从程序员的角度来看:

我能否假设 fread() 的返回值的 POSIX 措辞(如上所示)也适用于 C/C++/Windows/...,即 nhave

我能否假设 fwrite() 的返回值的 C 措辞(如上所示)也适用于 C++/Windows/POSIX/...,即 nhave

【问题讨论】:

  • 这有什么奇怪的? C 指定可能的结果在某个集合 S 中。POSIX 表示可能的结果在某个集合 T 中。T 是 S 的子集。因此,所有符合 POSIX 规范的结果也符合 C 规范。为什么会有“应该遵循 C 标准”的问题? T 符合。唯一的差异是这没有被记录为扩展。但我可以看到人们将扩展视为一种值得注意的额外行为,而不是简单地缩小可能性……
  • ... 例如,要求 int 为 32 位在技术上是 C 标准的扩展,但很少有人会在正式的数学上下文之外称其为。
  • 您是否观察到与所述内容相反的行为?还是您只是对文档的措辞感到困惑?请澄清是哪一个,并用您修改后的问题更新您的帖子和标题。
  • @EricPostpischil:因为在 fwrite() 的情况下,它与您所说的正好相反。 C 标准中规定的行为比 POSIX 和 MSDN 规定的更为严格。
  • @smac 在对标准措辞进行批评时,实际程序的证据不是必需的。 OP承认一个合理的原因是草率的写作; "only if" 和 "if" 等价 is 邋遢,它们有不同的含义。更重要的是,这个问题被标记为“语言律师”:它旨在了解什么标准以及什么程序和实现。如果您不喜欢讨论标准所说的内容,请不要评论、阅读或回答带有“语言律师”标签的帖子。抱怨他们在谈论措辞就像抱怨一个 java tagged question 谈论 java。

标签: c++ c language-lawyer posix stdio


【解决方案1】:

那么,这里发生了什么?只是草率的措辞?

我认为您对单词的解析过于精细,如果您愿意,可以将其描述为规范的草率措辞。

首先考虑fread()。 C17 说,

fread函数返回成功读取的元素个数, 如果读取错误或文件结束,则可能小于nmemb 遇到过。

我同意该措辞并未明确说明错误或文件结尾是要读取的项目少于请求的唯一原因,但如果这不是本意,那么为什么会出现错误和结尾-文件条件有没有提到?

fwrite 的 C17 措辞是明确的:

fwrite函数返回成功写入的元素个数,只有遇到写入错误才会小于nmemb。

比较两者,可以遵循两种不同的推理方式:

  1. 这两个功能是相似的,因此fread 的模棱两可的措辞应以与fwrite 明确指定的相同“仅当”含义解释,或者

  2. 如果有相同的解释,这两者会使用相同的措辞。

我发现第一个更有说服力,特别是考虑到它还解释了为什么 fread 文档甚至提到错误和文件结束条件。我完全准备好接受,尽管委员会的意图是最好的,但规范的语言并不完美。

【讨论】:

  • fread() 的最终目标是读取给定数量的给定大小的数据元素。因此,实现应该只在 EOF 或发生错误时过早返回。这将有利于您的第一个解释。但话又说回来,还是有点投机。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-11
  • 2014-08-12
  • 2011-04-20
相关资源
最近更新 更多