fseek / fsetpos可能会丢弃流缓冲区?

时间:2018-07-22 20:43:34

标签: c posix

在fopen的C标准中,有关在更新模式下打开的文件(C11 7.21.5.3/7),输出后跟输入要求对fflush或文件定位功能(fseek,fsetpos或rewind)的中间调用。但是,不需要任何文件定位功能就可以执行关于输出缓冲区的任何操作。

POSIX标准对fopen和更新模式保持相同的要求。与C标准一样,fsetpos不需要对输出缓冲区执行任何操作。但是,需要fseek才能将缓冲区写入文件。

对于C和POSIX,在调用fsetpos时,符合规范的实现似乎都可以随意丢弃写缓冲区,而C似乎允许fseek做到这一点。我的第一个问题是我是否错过了与标准相关的内容。这意味着可移植的应用程序必须调用fflush(或在POSIX的情况下为fseek / rewind),以确保在从输出切换到输入之前真正写了缓冲的输出。

很明显,丢弃写缓冲区与所有写函数的意图背道而驰,而且我不知道执行此操作的任何实现方式或任何与直觉相反的方式。我也意识到自己的意识有限,所以我的第二个问题是是否有任何兼容的实现方式不能确保最终将缓冲内容写到正确的位置。

对于上下文,GNU文档对fopen和更新模式保持相同的要求。与C和POSIX一样,fsetpos关于输出缓冲区什么也没说,但是我的测试表明我的版本确实刷新了缓冲区。但是,fseek可能会刷新缓冲区或记住足够多的缓冲区,以确保最终正确地写入缓冲区的内容。

TL; DR: C或POSIX是否禁止fsetpos丢弃写缓冲区?有实现的方法吗?

编辑:尚无人提供可靠的证据表明这两个标准都禁止fsetpos丢弃写缓冲区。同样,没有人提到任何实现此目的的实现。但是,C标准(附件J)中的可移植性问题列表中未提到这一点,这表明这是一个疏忽,而不是一个隐晦的可移植性问题。此外,正如R ..所提到的那样,没有禁止完全不相关的函数丢弃缓冲区的禁止条件。

3 个答案:

答案 0 :(得分:1)

fsetpos情况下,除了错误部分中的注释(两次)之外,我看不到需要刷新的任何内容:

  

的缓冲区需要刷新,

这看起来像是POSIX中的遗漏。请在Austin Group issue tracker中提出澄清要求。

答案 1 :(得分:1)

我看不出你从哪里得到这个主意。 POSIX在缓冲行为方面比C标准更为详细,因为POSIX必须处理stdio FILE流与其他访问同一文件的方式之间的交互。但是,在C标准中,没有任何东西表明在调用fsetpos时允许实现丢失输出。从逻辑上讲,数据已经被写入。

此外,fsetpos的规范(C11 7.21.9.3,¶2)读为:

  

如果发生读取或写入错误,则会设置流的错误指示符,并且fsetpos失败。

可能发生写错误的唯一可能原因是某种写操作,并且唯一可能的写操作是刷新挂起的输出。

答案 2 :(得分:0)

C标准似乎没有明确禁止fsetpos(或任何其他函数)丢弃该缓冲区,这似乎可以说是很简单的。但是,C99 Rationale文档(7.19.5.3)指出fsetposfseekrewindfflush“确保已刷新I / O缓冲区”。尽管人们可能会推测有关GNU和回写式高速缓存以及是否希望在搜索操作中强制使用磁盘I / O,但尚不清楚为什么该文本未包含在标准中。

在实践中,这意味着人们应该能够进行写入,查找,读取然后返回预期的数据。但是,考虑到至少有一个实现(GNU)在搜索时可能并不总是刷新,因此不应假定没有显式刷新请求,数据就已经到达内核(更不用说底层设备了)。