能否区分fgets返回的错误?

13

查看ISO C11标准关于fgets §7.21.7.2, 3的内容,其中关于代码概要中返回值已经说明:

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

fgets函数在成功时返回s。如果遇到文件结尾并且没有将任何字符读入数组中,则数组内容保持不变,并返回空指针。如果在操作期间发生读取错误,则数组内容是不确定的,并返回空指针。

标准规定,无论是遇到文件结尾并且没有读取任何字符,还是发生读取错误,都会返回空指针。我的问题是,仅从fgets和返回的空指针,是否有办法区分导致错误的两种情况?


我会怀疑ferror()有其存在的理由。 - too honest for this site
4
feof()ferror()函数是为此而设计的。请注意,while (!feof(file))始终是错误的 - Jonathan Leffler
注意,在你回答之前...“仅从fgets和返回的空指针”。 - Pushan Gupta
无论如何,如果您将输入缓冲区设置为全部为0,则还可以看到部分已读取的内容。 - Frankie_C
1
@Frankie_C--:“如果在操作期间发生读取错误,则数组内容是不确定的。” - ad absurdum
显示剩余2条评论
2个回答

9
如果失败是由文件结束条件引起的,还会在流上设置eof指示器(参见feof())。在这种情况下,str指向的数组的内容不会被更改。 如果失败是由其他错误引起的,则在流上设置错误指示器(参见ferror())。str指向的数组的内容是不确定的(甚至可能没有以null结尾)。
因此,您需要检查feof()和ferror()以确定错误。
来自于this site

9
有没有办法区分哪种情况导致了错误?
是的,使用 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";
}

第二个建议测试返回值是否为NULL,这是由OP提出的。
第一个可能会遇到一个罕见的问题。 ferror(stream)测试标志位。该标志可能已经被设置为stream上的先前的 I / O函数调用,因此fgets()不一定是错误的原因。最好检查fgets()的结果,以查看是否函数失败。
如果代码在检测到错误后继续使用stream,请务必在继续之前清除错误 - 例如尝试重新尝试。
if (ferror(stream)) {   
  clearerr(stream);
  return "Input error occurred");
}

请注意,clearerr() 函数会清除错误和文件结束标志位。
同样的,feof() 函数也会这样做,但是大多数代码都会在检测到文件结束后停止使用 stream
有第三种“病态”方法可以导致返回 NULL,而且 feof()ferror() 都无法返回 NULL。详见Is fgets() returning NULL with a short buffer compliant?。仔细阅读 C 语言规范中的三个条件语句,可能会发现其中没有一个条件满足,导致规范存在缺陷,这可能会引起未定义行为。

也许将字符串作为返回值并不是一个好的做法,因为程序可能包含国际化元素,所以最好定义一个错误代码的枚举并返回枚举值。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接