是否可以区分fgets返回的错误

Is it possible to distinguish the error returned by fgets

查看 fgets §7.21.7.2, 3 的 ISO C11 标准后,return 值是关于概要代码的:

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

The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned.

标准规定空指针被returned 用于文件结尾并且没有字符被读入或者发生读取错误。我的问题是,仅从 fgets 和 returned 空指针,有没有办法区分这两种情况中的哪一种导致了错误?

If the failure has been caused by end-of-file condition, additionally sets the eof indicator (see feof()) on stream. The contents of the array pointed to by str are not altered in this case. If the failure has been caused by some other error, sets the error indicator (see ferror()) on stream. The contents of the array pointed to by str are indeterminate (it may not even be null-terminated).

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

来自this site

Is there a way to distinguish which of the two cases caused the error?

是的,用feof()ferror()来区分。


但正确使用很重要。考虑两个代码:

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 的建议正确测试 return 值与 NULL

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

如果代码要在检测到错误后继续使用 stream,请务必在继续之前清除错误 - 比如可能会尝试重试。

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

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

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


有第三种病态接收NULL的方式,feof()ferror()都没有returnNULL 详见 Is fgets() returning NULL with a short buffer compliant?。仔细阅读 C 规范有 3 个 "ifs",其中可能没有一个是正确的,因为缺少规范 - 这意味着 UB。