【问题标题】:Why open a stream with fopen and perform I/O using read/write (not fread/fwrite)为什么使用 fopen 打开流并使用读/写(而不是 fread/fwrite)执行 I/O
【发布时间】:2023-03-28 01:59:01
【问题描述】:

在查看libstd++(GNU CC 4.9.2)中basic_filebuf 的实现时,我遇到了__basic_file 类,但我无法理解其设计原理。具体来说:

  1. __basic_file::open 使用 C stdio 实现 fopen
  2. __basic_file::sync 使用 C stdio 实现 fflush
  3. 所有其他方法都是使用系统调用实现的(例如readwritelseek

我知道为什么 I/O 是使用系统调用来执行的(filebuf / streambuf 实现了它们自己的缓冲)但是为什么要首先使用 C stdio 打开文件

为什么要刷新sync 中的stdio 缓冲区(这不会潜在地引入一些奇怪的边缘情况)?例如,如果由于某种原因 fwrite 除了执行 C++ 流写入外还被客户端代码调用,则可能不遵守写入顺序(即发生filebuf 写入,发生fwrite 但不会填充标准输入输出缓冲区并实际输出任何内容,filebuf 再次写入,sync 被显式或隐式调用...然后fwrite 数据将最后写入 - 我意识到这是一个人为的例子,但理论上可能)。

【问题讨论】:

  • 请在您的问题中添加您能想到的任何边缘情况。这将提高问题的质量。
  • @R Sahu:我添加了一个有些人为的例子,尽管“边缘情况”不是问题的重点。
  • 这可能是不鼓励混合 stdio 和 C++ 流的原因之一。

标签: c++ g++ libstdc++


【解决方案1】:

有一个标准函数 std::base_io::sync_with_stdio 可用于关闭原始 C io 和缓冲 C++ 内容的默认且可能代价高昂的同步。我现在没有确凿的证据,但我冒险猜测这意味着(通过逆逻辑)你的边缘情况已被涵盖。

【讨论】:

  • 好主意 - 让我阅读了大量代码。不幸的是,情况并非如此:sync_with_stdiostdio_sync_filebufstdio_filebuf 之间切换,用于标准 C++ 流(例如 cout 等)。现在前者是使用FILE 成员和预期的fread/fwrite 调用实现的。后者是对basic_filebuf 的改进。所以没有解释为什么__basic_file使用fopen/fflushread/write(而不是open和NOPsync)。
  • @isedev 你可以试试直接问@Jonathan Wakely,他一定知道详情。
【解决方案2】:

我仍然不知道为什么sync 实现了fflush,但我明白了为什么用fopen 打开文件:

  • 所有的文件访问方法,即使是通过readwritelseek等系统调用实现的,都调用fd方法来获取文件描述符;

    李>
  • fd 方法使用类的stdio FILE 成员上的fileno 来获取文件描述符。

如果FILE 结构与有效流不对应,现在fileno 将返回-1(无效文件描述符)。这意味着不需要在文件访问方法中实现任何逻辑来检查文件是否实际打开。

这避免了创建 __basic_file 然后关闭(未销毁),使用相同的文件描述符重新打开另一个文件(这是可能的,因为 open 使用最小的可用文件描述符)然后尝试针对已关闭的 __basic_file 进行 I/O(如果没有上述逻辑,实际上会导致针对不相关文件的 I/O)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    相关资源
    最近更新 更多