检查EOF和fgetc()错误的更好方法是什么?

ash*_*n33 7 c fgetc

我总是使用这种方法

int c;
while ((c = fgetc(fp))!=EOF)
{
    printf("%c", c);
}
Run Code Online (Sandbox Code Playgroud)

因为在我看来,它更具可读性和强大性.但是对于我的链接答案,chux评论说

if(feof(fp))比int c更健壮; while((c = fgetc(fp))!= EOF)

    while(1)
    {
        c = fgetc(fp);
        if ( feof(fp) )
        {
            break ;
        }
        printf("%c", c);
    }
Run Code Online (Sandbox Code Playgroud)

比第一个版本更强大.那么我应该使用什么版本?请解释一下为什么这个版本更好.

编辑

问题为什么"while(!feof(file))"总是错的?有人问为什么控制循环中的feof()总是错误的.但feof()以适当的方式检查条件是否总是错误的?解释很明显.

fuz*_*fuz 5

我通常编程输入循环如下:

int c;

while (c = fgetc(fp), c != EOF) {
    /* do something with c here */
}

/* check if EOF came from an end-of-file or an error */
if (ferror(fp)) {
    /* error handling here */
}
Run Code Online (Sandbox Code Playgroud)

您通常不应该使用这样的循环条件:

while (!feof(fp)) {
    /* do stuff */
}
Run Code Online (Sandbox Code Playgroud)

要么

for (;;) {
    c = fgetc(fp);
    if (feof(fp))
        break;
}
Run Code Online (Sandbox Code Playgroud)

因为遇到IO错误时会中断.在这种情况下,fgetc返回EOF但未设置文件结束标志.您的代码可能会进入无限循环,因为错误条件通常会持续到执行外部操作.

正确的方法是检查结果fgetc():如果它等于EOF,你通常可以停止读取更多数据,因为在IO错误和文件结束条件的情况下,通常无法读取更多数据.然后,您应检查是否发生错误并采取适当的措施.

  • OP要求*解释*. (7认同)

chu*_*ica 5

2 有趣的问题

ferror()

ferror()反映错误指示符的状态。该标志在发生罕见的输入错误时置位,并保持置位直到清除 - 参见clearerr()。如果一次读取输入错误并且代码稍后再次读取,不清除ferror()仍然报告 true,即使接下来的读取没有错误。

fgetc()返回EOF它可能是由于最终的文件(公共)或稀有输入错误。检查feof()胜于ferror()区分。 ferror()由于先前的错误而不是当前的情况,这可能是真的 - 这肯定是文件结尾。

int c;
c = fgetc(file);
if (c == EOF) {
  if (feof(file)) puts("end-of-file");
  else puts("input error");
}
Run Code Online (Sandbox Code Playgroud)

Widechar:由于C 中的一个极端情况,出现了测试错误条件的问题。

fgetc()返回一个int. 其值在该范围unsigned charEOF,(一些负数)。

int ch;
while ((ch = fgetc(fp)) != EOF) {
  // do something with ch
}
if (ferror(fp)) Handle_InputError();
if (feof(fp)) Handle_EndOffFile();  // Usually nothing special
Run Code Online (Sandbox Code Playgroud)

然而 C 允许unsigned char具有比 的正数更宽的范围int。将 an 转换unsigned charint具有实现定义的行为,这可能会导致unsigned char值转换为负数int- 并且匹配EOF

这样的平台比较少见,也不是2015年的主流。大部分都会有UCHAR_MAX <= INT_MAX,上面的风格比较典型。令人怀疑的是,由于依赖于EOFunsigned char转换为int.

如果代码需要处理罕见的情况 where UCHAR_MAX > INT_MAX,那么

int c;
for (;;)
{
    c = fgetc(file);
    if (c == EOF) {
      if (feof(file)) break;
      if (ferror(file)) break;
      // fall through if both if's fail.
    }
    // do stuff with c
}
Run Code Online (Sandbox Code Playgroud)

while ( !feof (file) ) 中的流行参考总是错误的?突出显示代码在使用fgetc(in)检查问题之前的结果时经常犯的错误。上面的两个代码在使用fgetc().


第二个代码处理所有情况,包括那些可能只适用于坐在一些早已被遗忘的垃圾堆中的计算机的情况。第一种更为常见。