【发布时间】: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 字节)。
MSDN 和cppreference.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),但需要检查。
MSDN 和cppreference.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