我对 C 语言中 EOF(文件末尾)的理解是否正确?

Is my understanding of EOF (end of file) in C correct?

提问人:professional pro 提问时间:8/31/2022 最后编辑:professional pro 更新时间:8/31/2022 访问量:475

问:

假设我们有这段代码:

while ((ch = getc(fp)) != EOF) {
  ...
}

这就是我假设循环会工作的方式,请告诉我它是否正确/是否犯了任何错误:

  1. getc从 I/O 流中读取字符fp
  2. getc将其存储在变量中ch
  3. ch测试通常等同于(取决于它如何为您定义)。EOF-1
  4. 当返回时,它表示已设置特定流的指示器。这意味着之前的读取操作已尝试读取文件末尾。EOFEnd Of File

我有一个重要的问题:

在这个循环中,当到达文件的末尾时,它是否试图最终读取文件的末尾,从而导致它最终返回?getcEOF

C 文件 指针 EOF GETC

评论

3赞 Shawn 8/31/2022
ch如果还没有,则需要是。int
0赞 professional pro 8/31/2022
让我们假设在这种情况下。
0赞 Shawn 8/31/2022
将其设为 .有关详细信息,请参阅 c-faq.com/stdio/getcharc.htmlchar
0赞 Eric Postpischil 8/31/2022
当返回时,并不一定意味着文件结束。 如果发生错误,例如,如果输入硬件报告了错误,也会返回。getcEOFEOF
0赞 professional pro 8/31/2022
真的@EricPostpischil?这当然非常令人困惑,我以为这只是因为上次的读取尝试超过了文件末尾。EOF

答:

1赞 Jonathan Leffler 8/31/2022 #1

一旦文件流到达 EOF,状态就应该是粘性的——文件流上的所有输入操作都会在每次调用它们时报告 EOF。 您可以调用以重置错误/EOF 状态,在这种情况下,输入函数将尝试读取更多数据,直到它们再次遇到 EOF。clearerr()

曾经有一段时间,如果输入设备是终端,GNU C 库不会使状态具有粘性。如今,情况已不再如此。

1赞 Barmar 8/31/2022 #2

不,它永远不会尝试读取文件的末尾,因为当您到达末尾并且循环停止时,条件会失败。当上一次迭代读取文件的最后一个字符时,就会发生这种情况,因此您位于末尾,而不是过去。ch != EOF

如果您继续尝试阅读,除非您致电,否则它会继续返回。这在处理扩展的文件时很有用(想想命令是如何工作的 - 它读取直到 EOF,然后继续检查文件是否增长)。EOFclearerr()tail -f

评论

0赞 professional pro 8/31/2022
because the ch != EOF condition fails when you get to the end但是我以为当上一次读取尝试尝试读取文件末尾时会返回吗?EOF
0赞 Barmar 8/31/2022
不,您将它与函数混淆了。feof()
0赞 professional pro 8/31/2022
啊,我明白了,所以返回以指示文件末尾,即不再来自流的输入。并且可以用来区分我们是否真的命中了,或者之前的读取操作是否导致我们当前的操作失败?这是对的吗?EOFfeofEOF
0赞 Barmar 8/31/2022
有关问题,请参阅 stackoverflow.com/questions/5431941/...feof()
1赞 Barmar 8/31/2022
不同之处在于,当您尝试读取文件末尾时,会返回该内容。 不会尝试读取任何内容,因此它会返回有关上一次读取的信息。EOFfeof()
1赞 Eric Postpischil 8/31/2022 #3
  1. getc从 I/O 流中读取字符fp

更准确地说,尝试从流中读取字符。getcfp

  1. getc将其存储在变量中ch

getc返回一个值,赋值将该值存储在 中,如果它在类型中可表示。如果它不可表示,则以取决于类型的方式进行转换。为避免此转换的复杂性,应为 。intch = getc(fp)chchchchint

  1. ch经过测试...EOF

是的,将 的结果值与 进行比较。这使得类型很重要:如果返回 和 是不能表示 的值的字符类型,则转换将导致将不同的值存储在 中,然后它不会与 进行比较。chEOFgetcEOFchEOFchEOF

...这通常等同于(取决于它是如何为你定义的)。-1

EOF在许多 C 实现中可能是 −1,但它具有任何负值是正常的。int

  1. 当返回时,它表示已设置特定流的指示器。EOFEnd Of File

否,返回表示已到达文件末尾(并尝试进一步读取)或发生错误。C 2018 7.21.7.5 3说道:EOF

该函数从 指向的输入流中返回下一个字符。如果流位于文件末尾,则设置流的文件末尾指示符,getc 返回 。如果发生读取错误,则设置流的错误指示器并返回 。getcstreamEOFgetcEOF

这意味着之前的读取操作已尝试读取文件末尾。

这意味着上一个操作或当前操作试图读取文件末尾,或者上一个操作或当前操作遇到错误(并且这些先前的条件尚未清除,如通过调用 或 )。rewindclearerr

在这个循环中,当到达文件的末尾时,它是否试图最终读取文件的末尾,从而导致它最终返回?getcEOF

如果流连接到大小有限且不变的文件,则该循环最终将尝试读取文件末尾,如果循环主体中没有任何内容重置文件位置,则此时将返回并退出循环。但是,如果流连接到某些“无限”数据供应,例如管道,则循环可能永远不会遇到流的末尾。EOF

评论

0赞 professional pro 8/31/2022
多么了不起的答案,谢谢@EricPostpischil