与 == EOF 与 feof 的混淆

Confusion with == EOF vs feof

提问人: 提问时间:3/23/2016 最后编辑:lost_in_the_source 更新时间:5/24/2022 访问量:10489

问:

我打开了一个文件,在指针的地址下找到了流。我正在尝试查看文件是否为空。使用以下内容ptr

if (fgetc(ptr) != EOF)

按预期工作。当文件为空时,不执行该语句。当文件不为空时,不执行语句。

但是,使用

if (!feof(ptr))

始终执行语句。

为什么会这样?有没有办法使用该功能?feof

C 文件 指针 FGETC FEOF

评论

7赞 lost_in_the_source 3/23/2016
EOF 指示器是在读取失败设置的。
5赞 Weather Vane 3/23/2016
请参阅为什么“while ( !feof (file) )”总是错的?

答:

7赞 jdarthenay 3/23/2016 #1

feof(f)将始终在打开文件后立即返回,因为 if 为您提供一个标志的值,该标志初始化为 false 并仅在至少一个读取操作失败后设置为 true。false

3赞 user4815162342 3/23/2016 #2

你可以这样使用:feof

fgetc(fp);
if (feof(fp))
  ...

feof检查在读取后设置的文件结束指示器,该指示器试图在文件末尾或超过文件末尾读取。当您无法控制的代码从文件中读取,并且您希望在文件用尽后停止处理时,它非常有用。

评论

1赞 chqrlie 3/23/2016
投了反对票,因为即使有正确的解释,也不应该鼓励新手使用。怎么了?feof()if (fgetc(fp) == EOF)
3赞 M.M 3/23/2016
这样做的问题是,返回 EOF 表示任何错误条件,但仅检查文件末尾的特定条件。因此,如果出现读取错误但文件未结束,则您的代码将继续对虚假数据执行操作。fgetcfeof
1赞 Jerry Jeremiah 3/23/2016
我了解它是如何工作的 - 告诉我阅读手册页是居高临下的。打开文件意味着已找到该文件,并不意味着包含数据的扇区具有有效的校验和。假设读取错误意味着文件为空,如果空文件具有语义含义,则会带来麻烦。如果知道文件是否为空很重要,那么您需要实际测试该特定条件。在程序在任何情况下都无法停止的嵌入式系统中,让程序在任何情况下都能正常工作非常重要。
1赞 user4815162342 3/23/2016
@chqrlie 除了通过将EOF与其他读取错误混为一谈而产生误报的问题外,答案还解释了问题上下文中的作用,而不必为该特定情况背书。最后一句话是重要的一点,解释了为什么实际上有用,这对 OP 来说并不明显。fgetc(fp) == EOFfeoffeof
1赞 user4815162342 3/23/2016
@chqrlie EOF 与错误参数只是我评论的一部分(除了......),我个人同意这并不是那么重要。考虑到“经常被误用”并不意味着我们不能向初学者解释它的作用。OP明确询问了如何使用,答案对此进行了解释。除了你普遍不喜欢之外,答案中还有问题吗?feoffeoffeof
11赞 AnT stands with Russia 3/23/2016 #3

在 C 标准库中,“文件结束”不是一个独立的自检测条件。“文件结束”只是由前面的读取操作设置的文件状态。在执行读取操作之前,直到该读取操作碰到文件的实际末尾,否则不会设置“eof”状态并返回 0。feof()

C 标准库中的许多(大多数)标准 I/O 函数已经返回了一些可用于检测“文件结束”条件(如返回值)的完成代码。这意味着大多数时候调用是不必要的。fgetc()EOFfeof()

换句话说,如果你把“文件末尾”看作是一堵砖墙,那么在C标准库中,仅仅站在那堵墙的正前方来检测它是不够的。有必要用你的额头撞到那堵墙,以发现它的存在。

当您打开一个空文件时,您从“就在墙前”的状态开始。此时尚未检测到“文件结束”条件。你必须尝试阅读一些东西,才能撞到那堵墙,从而检测到它的存在。

这种设计的原因完全合乎逻辑。C 语言旨在支持各种输入流和文件系统,包括 1) 根本不存储文件大小的文件系统,以及 2) 只知道近似文件大小的文件系统(例如四舍五入到最近的集群)。在此类文件系统中,文件的末尾通常由特殊标记指定。你不知道那个标记在哪里,直到你在阅读文件时遇到它。(出于同样的原因,C 流不保证支持从函数中的原点定位。SEEK_ENDfseek

正如@Barmar在评论中指出的那样,没有预先确定的“文件结束”位置的输入流的一个更好的例子是链接到终端的标准输入。

评论

2赞 Barmar 3/23/2016
为了增加您的原因,它可能根本没有从文件系统读取。它可以从终端、管道、网络流等读取。这些没有文件大小。
0赞 chqrlie 3/23/2016
这是一个详细的解释,但您应该扩展输入失败和文件结束条件之间的区别:当读取操作失败时,例如 ,这可能意味着已到达文件结束或某种读取错误。 然后可用于确认文件末尾是否导致失败。这应该是它的唯一目的。fgetc() == EOFfeof()
15赞 Keith Thompson 3/23/2016 #4

有没有办法使用该功能?feof

是的,有。输入函数返回一个值以指示它没有更多要处理的输入后,您可以调用和/或确定该条件是由到达输入末尾还是某些错误条件引起的。feof()ferror()

这是 and 函数的唯一有效用途。feof()ferror()

指示不再保留输入的结果因函数而异。例如,返回值 ,返回一个空指针,并返回小于请求的记录数的某个值。您需要阅读每个输入函数的文档以了解其工作原理。fgetc()EOFfgets()fread()

评论

0赞 Weather Vane 3/23/2016
fread返回小于请求的仅表示返回 0 时的 EOF 等效。
1赞 Keith Thompson 3/23/2016
@WeatherVane:我不认为这是正确的。你在想吗?引用 C 标准:“fread 函数返回成功读取的元素数,如果遇到读取错误或文件末尾,则该数可能小于 nmembread()
0赞 Weather Vane 3/23/2016
不。返回的非 0 值不是 EOF,而是有效读取。返回的 0 值是 EOF。
1赞 Keith Thompson 3/23/2016
@WeatherVane:这几乎是等价的。 就像通过反复调用 .例如,如果您请求读取 10 条记录,而它返回 5 条,则表示它尝试读取第 6 条记录但失败,要么是因为存在错误,要么是因为它到达了输入流的末尾。fread()fgetc()fread()
3赞 dave_thompson_085 3/23/2016
对于 EOF 或错误返回 EOF; 返回 null 指针; 返回 <N。fgetcfgetsfread
0赞 S3DEV 5/23/2022 #5

然而,迟到的回答是添加 Stephen Kochan 的 Programming in C(第 4 版)第 367 页的有用引用:

记住,告诉你已经尝试阅读过去 文件的末尾,这与告诉你你只是 从文件中读取最后一个数据项。您必须读取最后一个数据项才能返回 零。feof()feof()

斜体我的。