'fseek'、'fsetpos' 和 'rewind' 是否刷新 C 中的缓冲区?

Do `fseek`, `fsetpos`, and `rewind` flush the buffer in C?

提问人:Christopher Miller 提问时间:7/12/2023 最后编辑:Christopher Miller 更新时间:7/13/2023 访问量:83

问:

C 参考指出,在更新模式下打开的 ('+') 需要采取以下两项预防措施:FILE*

  • 输出后跟输入后不能调用 、 、 或 。fflushfseekfsetposrewind
  • 输入后不能跟输出,除非调用 、 或 。fseekfsetposrewind

我了解到,这足以允许在输出后输入,因为打开模式通常使用相同的缓冲区进行读取和写入操作。因此,不使用 before input 可能会导致错误地从缓冲区读取数据(缓冲区可能尚未刷新,因此包含仍需要输出的数据)。fflushFILE*+fflush

但是,为了实现 、 和 达到相同的效果,这意味着它们必须在内部刷新传递给它们的流的缓冲区。fseekfsetposrewind

C 标准是否要求 fseekfsetposrewind 刷新其流的缓冲区?如果不是,为什么不呢?

C 文件 刷新 fseek fflush

评论


答:

0赞 chux - Reinstate Monica #1

仅供参考

当使用更新模式(“+”作为上述模式参数值列表中的第二个或第三个字符)打开文件时,可以在关联的流上执行输入和输出。但是,输出后不应直接跟着输入,而不对函数或文件定位函数 (, , or ) 进行干预调用,并且输入后不应直接跟随输出,而无需对文件定位函数进行干预调用,除非输入操作遇到文件末尾。在某些实现中,使用更新模式打开(或创建)文本文件可能会打开(或创建)二进制流。
C23dr § 7.23.5.3 7
fflushfseekfsetposrewind

0赞 Nate Eldredge 7/13/2023 #2

在 C17 标准中,对于“刷新”,保证刷新缓冲区的唯一操作是 、 、 和 return from 。此外,它是否执行刷新是由实现定义的。没有迹象表明,朋友可以保证这样做。fclose()fflush()exit()mainabort()_Exit()fseek()

调用 etc 的要求是允许原始的 stdio 实现,这些实现不跟踪上一个操作是读取还是写入,也不跟踪缓冲区是否脏或有多少脏。但是,更智能的实施可能会很好地跟踪。在这种情况下,无需执行刷新,因为后续读/写操作将根据需要完成刷新。该标准没有充分的理由通过要求在不需要的地方进行刷新来破坏此类优化。fseekfseek

如果程序员特别希望缓冲区被刷新,他们应该只调用,而不是依赖 seek 为他们做这件事。即使它恰好在特定实现上是冗余的,额外的成本也应该可以忽略不计,因为刷新已经为空的缓冲区应该什么都不做。fflush()