fgetc return EOF 是否在到达文件末尾后每次调用?

Does fgetc return EOF on every call after end-of-file reached?

给定以下 C 代码:

int eofCount = 0;
while (true) {
    int c = fgetc(stdin); 
    if (c == EOF) eofCount++;
}

eofCount 会大于 1 吗?

我在 C 文档中找不到任何描述达到 EOF 后 fgetc 会发生什么的内容。我知道我可以自己记账,但如果 stdlib 帮我做,那就太好了。

我不是在寻找代码片段,因为我已经用 glibc 尝试过这个,事实上 eofCount 递增超过了 EOF。我想要 stdlib 源代码参考或规范来确认这是定义的行为。依赖未定义的行为可能会导致问题。

是的,计数会大于 1,因为您有一个无限 while 循环。你会发现 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf and http://pubs.opengroup.org/onlinepubs/9699919799/ 很有用。

试试这个:

#include <stdio.h>
#include <stdbool.h>

int main() {
    int eofCount = 0;
    /*while (true) {*/

    int c = fgetc(stdin); 
    if (c == EOF) eofCount++;
        c = fgetc(stdin); 
    if (c == EOF) eofCount++;
        c = fgetc(stdin); 
    if (c == EOF) eofCount++;

    /*}*/

printf("%d\n", eofCount);
return 0;

}

编译并运行。在 Linux 上按 ctrl+D 两次,然后输入。你会得到2.

这是用 gcc -ansi -Wall -Werror -pedantic test.c 编译的,因此它满足 ANSI,即 C89 标准。

只要您不是从交互式 Linux 终端读取(即您不打开文件或从其他 file/process 传输标准输入),一旦您读取 EOF,所有未来的读取也将读取 EOF。

如果您从 Linux 终端阅读,按下 EOF 键序列(Linux 上的 CTRL-D)将读作 EOF,但您仍然可以输入更多字符并阅读它们.

来自 C standard 的第 7.21.7.1 节:

3 If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF.

Does fgetc return EOF on every call after end-of-file reached?

这取决于 2 个 指标 和 I/O 函数调用。


尽管 OP 未提及,但有两个原因导致 fgetc(stdin); returns EOF 以及它们如何影响后续 fgetc() 调用不对称。此外,使用各种 I/O 函数会影响 2 指标 ,进而影响后续 fgetc() 调用

文件结束。
输入错误。


C 规范在 文件结束指示器 上是明确的,导致后续 EOF

If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the fgetc function obtains that character ... C11 §7.21.7.1 2

当文件结束发生或已经发生时,将设置持久标志:文件结束指示器,因此对fgetc()的后续调用将return EOF.

If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returnsEOF ... §7.21.7.1 3


当发生罕见的输入错误时,fgetc() returns EOF,但该事件不会设置 文件结束指示器 ,但设置了 错误指示符 。后续调用不一定 return EOF,即使设置了 错误指示符 。 IMO,C 规范在这一点上不够明确。

If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF §7.21.7.1 3


feof()ferror() 的调用可用于区分导致 EOF 的原因,但也可能反映先前的 I/O activity。因此,好的代码会在 EOF 被 returned 后立即检查这些函数,并在 I/O 之后清除它们。


文件结束指示符错误指示符可以用void clearerr(FILE *stream);

清除

rewind()函数清除错误指示器

ungetc() 将清除 文件结束指示符

其他 I/O 函数也会影响这些指标。


如果导致第一个 EOF 的条件被移除并且相应的指示符被清除,则对 fgetc() 的后续调用可能不会 return EOF