【问题标题】:Is it possible to distinguish the error returned by fgets是否可以区分fgets返回的错误
【发布时间】:2017-07-23 04:33:22
【问题描述】:

在查看fgets §7.21.7.2, 3 的 ISO C11 标准时,返回值与概要代码有关:

#include <stdio.h>
char *fgets(char* restrict s, int n, FILE* restrict stream);

如果成功,fgets 函数会返回 s。如果遇到文件结尾并且没有字符被读入数组,则数组的内容保持不变并返回一个空指针。如果在操作过程中发生读取错误,则数组内容不确定,返回空指针。

该标准规定,对于文件结束返回空指针并且没有读入任何字符或发生读取错误。我的问题是,仅仅从fgets,以及返回的空指针,有没有办法区分这两种情况中的哪一种导致了错误?

【问题讨论】:

  • 我怀疑ferror() 是有原因的。
  • 函数feof()ferror() 就是为此而设计的。请注意while (!feof(file)) is always wrong.
  • 请注意,在您回答之前...“仅来自 fgets,以及返回的空指针”
  • 无论如何,如果您将输入缓冲区设置为全 0,您还可以看到已部分读取的内容。
  • @Frankie_C--“如果在操作过程中发生读取错误,则数组内容不确定”。

标签: c fgets eof feof ferror


【解决方案1】:

有没有办法区分这两种情况中的哪一种导致了错误?

可以,用feof()ferror()来区分。 @Nothing Nothing


然而,正确使用很重要。考虑两个代码:

char buf[100];
fgets(s, sizeof s, stream);
if (feof(stream)) return "End-of-file occurred";
if (ferror(stream)) return "Input error occurred"; 


if (fgets(s, sizeof s, stream) == NULL) {
  if (feof(stream)) return "End-of-file occurred";
  if (ferror(stream)) return "Input error occurred"; 
  return "Should never get here";
}

第二个根据 OP 的建议正确测试 NULL 的返回值。

第一个可能会遇到一个罕见的问题。 ferror(stream) 测试一个标志。此标志可能已由stream 上的prior I/O 函数调用设置,因此此fgets() 不一定是错误的原因。最好检查fgets() 的结果,看看 this 函数是否失败。

如果代码要在检测到错误后继续使用stream,请务必在继续之前清除错误 - 就像尝试重试一样。

if (ferror(stream)) {   
  clearerr(stream);
  return "Input error occurred");
}

请注意,clearerr() 会清除错误和文件结束标志。

这同样适用于feof(),但大多数代码都是在文件结尾为真时使用stream 编写的。


有第三种病态方式来接收NULLfeof()ferror() 都不会返回NULL,详见Is fgets() returning NULL with a short buffer compliant?。仔细阅读 C 规范有 3 个“如果”,其中没有一个可能是正确的,因此规范缺少 - 这意味着 UB。

【讨论】:

    【解决方案2】:

    如果失败是由文件结束条件引起的,则额外设置 eof 指示符(参见 feof())。在这种情况下,str 指向的数组的内容不会改变。 如果失败是由其他错误引起的,则在流上设置错误指示器(请参阅 ferror())。 str 指向的数组的内容是不确定的(它甚至可能不是以 null 结尾的)。

    因此,您需要检查feof()ferror() 以确定错误。

    来自this site

    【讨论】:

      猜你喜欢
      • 2013-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 2019-02-25
      相关资源
      最近更新 更多