fgetc,检查EOF

13

在书籍 Linux系统编程 中,我读到了类似以下内容的描述:

fgetc 返回读取的字符作为无符号字符转换为 int 或者在文件结束或出错时返回 EOF。使用 fgetc 的一个常见错误是:

char c;
if ((c = fgetc()) != EOF) {...}

这段代码的正确版本是:

int c;
if ((c = fgetc()) != EOF) { printf("%c", (char)c); ... }
那么,为什么我不能将返回值强制转换为char,然后再与EOF进行比较呢?我为什么必须准确地用int来比较EOF?因为EOF被定义为-1,它不是通常强制转换为char吗?是否有平台/编译器,这种说法不成立?

可能是["while( !feof( file ) )" is always wrong]的重复问题 (https://dev59.com/jG035IYBdhLWcg3wbPU5) - jww
@jww:这个问题没有使用 feof(),因此它不是 "while (!feof(file)) is always wrong" 的重复。 - Jonathan Leffler
2个回答

12
由于返回值可能是EOF,而EOF的值是与系统相关且不等于任何有效字符代码,因此无法将返回值转换为char。通常情况下,它是-1,但不应假设如此。请查看c-faq-site中的这个很棒的答案:

如果像上面的片段那样,将getchar的返回值赋给一个char,则可能出现两种故障模式。

  1. 如果char类型是有符号的,并且如果EOF被定义(通常情况下)为-1,则具有十进制值255(在C中为'\377'或'\xff')的字符将被符号扩展,并将等于EOF,从而过早地终止输入。(假设8位char)。

  2. 如果char类型是无符号的,则实际的EOF值将被截断(通过丢弃其高阶位,可能导致255或0xff),并且不会被识别为EOF,从而导致输入效果无限。

link 希望能够帮到你! 编辑:(添加了@FatalError在此答案上的评论,c-faq网站上也有解释,但这个更清晰明了。) “如果将其转换为char,则EOF将取相同的值作为某些有效字符,因此变得无法与该字符区分开来。这本身足以证明不应将结果作为char。”@FatalError评论。

那又怎样?我不明白。在强制转换后,char会等于“-1”,是吗? - pproger
@pproger 标准实际上并没有规定char是有符号还是无符号的。如果你想要一个保证有符号的char,你必须使用signed char - Corbin
4
如果将其转换为char,那么EOF将具有与某个有效字符相同的值,因此无法与该字符区分开来。仅凭这一点就足以证明不应将结果作为char类型返回。 - FatalError
@pproger 正确。正如cacho所提到的,通常是这样的,但我认为标准只要求它为负数,并没有指定为-1。 - FatalError
@FatalError,我已经将您的评论添加到答案中,希望这不是问题... - Cacho Santa
显示剩余3条评论

5
当您在将值分配给char之前与EOF进行比较时,有两种可能性:
  • char是带符号值。在这种情况下,存在一个合法的字符(通常是ÿ,带分音符的小写拉丁字母Y,U + 00FF),它将被误解为EOF。
  • char是无符号值。在这种情况下,EOF将被转换为0xFF,然后作为正值提升到int,这永远不会等于作为负值的EOF。
无论哪种方式,该程序都会有时表现不良。
存在(更准确地说,曾经存在)编译器错误的可能性,即分配正确但未使用于比较的值。这会导致代码似乎正常工作,即使不是这样也是如此。幸运的是,在现代编译器中,这不太可能成为问题。

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