C语言 fgetc 在到达文件末尾后是否在每次调用时返回 EOF?



给定以下C代码:

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

eofCount 会大于 1 吗?

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

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

只要您不是从交互式 Linux 终端读取(即您不从其他文件/进程打开文件或管道 stdin),一旦您读取 EOF,所有将来的读取也将读取 EOF。

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

从C标准第7.21.7.1节:

3如果设置了流的文件结束指示器,或者流位于文件末尾,则流的文件结束指示器为 设置和fgetc函数返回EOF。否则,fgetc函数返回指向的输入流中的下一个字符 按流。 如果发生读取错误,则错误指示器 设置流,fgetc函数返回EOF

fgetc 在文件结束后是否在每次调用时返回 EOF?

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


虽然OP没有提到,但fgetc(stdin);返回EOF以及它们如何影响fgetc()调用不对称的原因有两个。 此外,使用各种 I/O 函数会影响 2 个指标,进而影响后续fgetc()调用

文件结尾。
输入错误。


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

如果未设置流指向的输入流的文件结束指示器,并且存在下一个字符,则 fgetc 函数将获取该字符...C11 §7.21.7.1 2

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

如果设置了流的文件结束指示器,

或者流位于文件末尾,则设置流的文件结束指示器,fgetc函数返回EOF... §7.21.7.1 3


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

如果发生读取错误,则设置流的错误指示器,fgetc函数返回EOF§7.21.7.1 3


调用feof()ferror()可以用来区分导致EOF的原因,但也可以反映先前的I/O活动。 因此,好的代码在返回EOF后会立即检查这些函数,并在发生以下 I/O 时清除它们。


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

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

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

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


如果删除导致第一个EOF的条件并清除相应的指示器,则对fgetc()的后续调用可能不会返回EOF

是的,计数将大于 1,因为您有一个无限的while循环。您会发现 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 和 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("%dn", eofCount);
return 0;

}

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

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

最新更新