fgetc(): 只检查EOF是否足够吗?

8

在网上找到的各种示例中,fgetc() 被用于以下方式:

FILE *fp = fopen(PATH, "r");

if (fp == NULL) {
    perror("main");
    exit(EXIT_FAILURE);
}

int ch;

while (ch = fgetc(fp) != EOF) {
    // do something
}

但是根据fgetc()的手册

如果发生读取错误,流的错误指示器将被设置,fgetc()将返回EOF,[CX]并设置errno以指示错误。

那么我也需要检查这个吗?如何检查?


4
你需要在赋值语句周围加上括号:while ((ch = fgetc(fp)) != EOF),但加上这个修复后,只需检查EOF就足够了。你会在错误或实际文件结束时得到EOF;如果需要的话,你可以在循环后消除这两种情况的歧义。 - Jonathan Leffler
3个回答

10
这是规范上的说明:
fgetc()函数应该获取下一个字节并将其转换为int类型的unsigned char。
以下宏名应定义为负整数常量表达式:EOF。
只要将返回值存储在int而不是char中,就足以检查EOF,因为保证EOF不表示有效的字符值,这样更加方便。
此外,在您的代码中,应该这样写:
while (ch = fgetc(fp) != EOF)

should be:

while ((ch = fgetc(fp)) != EOF)

额外的括号是必需的,因为!=的优先级高于=

8

您可以在 while 循环结束后立即使用 ferror(3) 进行检查:

while (EOF != (ch = fgetc(fp)))
   // do something

if (ferror(fp) != 0)
   // error handling

ferror函数在发生错误时会返回非零值。

如果您想在发生错误后继续使用fp,您需要使用clearerr函数清除错误标记:

clearerr(fp);

7
@Helper Method:你在你的man页摘录中引用了那个陈述。 - President James K. Polk

6
循环直到 fgetc 返回 EOF 是完全可以的。之后,如果你想知道循环是因为简单地到达文件结尾而结束,还是因为出现错误而结束,你应该调用 ferrorfeof。如果你不在意,可以跳过这个调用。
请注意,检查 feof 还是 ferror 是有区别的,因为流的错误标志是粘性的,即使遇到 eof 是 fgetc 失败的原因时,也可能评估为 true。通常应该使用 feof 进行检查,如果它返回 false,则可以得出循环停止是由于新错误导致的结论。

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