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

我总是使用这种方法

int c; while ((c = fgetc(fp))!=EOF) { printf("%c", c); } 

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

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

  while(1) { c = fgetc(fp); if ( feof(fp) ) { break ; } printf("%c", c); } 

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

编辑

问题为什么“while(!feof(file))”总是错的? 有人问为什么控制循环中的feof()总是错误的。 但是,如果条件适当地检查feof()总是错误的? 解释很明显。

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

 int c; while ((c = fgetc(fp)) != EOF) { /* do something with c here */ } /* check if EOF came from an end-of-file or an error */ if (ferror(fp)) { /* error handling here */ } 

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

 while (!feof(fp)) { /* do stuff */ } 

要么

 for (;;) { c = fgetc(fp); if (feof(fp)) break; } 

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

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

由于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 

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

此类平台很少见,并且不在2015年的主流中。大多数将具有UCHAR_MAX <= INT_MAX并且通常使用上述样式。 令人怀疑的是,由于代码量如上所述,这些平台将变得普遍,这依赖于EOF与转换为int unsigned char不同。

如果代码需要处理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 } 

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


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

建议的改进并不是更好,甚至更不稳健。

如此处所解释的,如果发生读取错误(没有eof),它将进入无限循环。 在这种情况下,当fgetc返回EOF时, feof将返回0

您的版本没有此问题。

此外,您的版本更短,更简单,更标准。