【问题标题】:Why Input functions cannot follow output functions or vice versa in C?为什么输入函数不能跟随输出函数,反之亦然?
【发布时间】:2019-01-07 01:10:24
【问题描述】:

我的课本上说:

“如果没有对 fflush、fseek、fsetpos 或 rewind 的介入调用,输入函数不能跟随输出函数,反之亦然 流 I/O 的第一个限制可以通过采用在每次输入操作之前刷新缓冲区的规则来解决。但是,解决第二个限制的唯一方法是在同一个打开的套接字描述符上打开两个流,一个用于读取,一个用于写入。”

所以我的问题是:

  1. 为什么输入函数不能跟随输出函数,反之亦然?
  2. 为什么不能通过添加 fflush 操作来修复第二个限制?

【问题讨论】:

  • 如果在同一个流上进行读写操作,必须确保操作彼此一致(例如,在写入流后,确保从该流的下一次读取从您期望的位置开始它到)。调用fflush() 等是确保一致性的手段。但是,该描述似乎特定于特定操作系统。也就是说,通常有比在单个流上交错读取和写入更好的选择。
  • fflush 仅对未输入最后操作的输出流或混合模式流定义了行为;否则它的行为是不确定的。
  • @Peter:描述直接参考C标准。特定的操作系统可能有宽松的条件(例如,Linux 在输入上定义fflush(),或者某些操作系统/库完全消除了这些限制)。但是一个完全符合标准的程序可能不依赖它,因为它是不可移植的。
  • @DevSolar - OP 引用的描述描述了在同一个打开的套接字描述符上打开两个流的“第二个限制”的解决方法。那不是标准的 C。

标签: c io


【解决方案1】:

C 标准说了一些类似的话,你的书大概是在转述它所说的内容:

C11¶7.21.5.3 The fopen function

¶7 当文件以更新模式打开时('+' 作为上述模式参数值列表中的第二个或第三个字符),可以在关联的流上执行输入和输出。但是,如果没有对fflush 函数或文件定位函数(fseekfsetposrewind)的干预调用,则输出不应直接跟在输入之后,并且输入不应直接跟在输出之后没有对文件定位函数的干预调用,除非输入操作遇到文件结尾。在某些实现中,使用更新模式打开(或创建)文本文件可能会打开(或创建)二进制流。

规则允许图书馆控制事情。它可能必须清理ungetc() 推回的字符,或者安排刷新输出以便可以正常完成输入,或其他任何事情。请注意,这些规则适用于文件流 (FILE *)。大多数情况下,当您使用套接字时,您使用的是文件描述符 (int),而不是文件流,这些规则根本不适用。

请注意,fseek(fp, 0, SEEK_CUR) 是一种定位操作,它会将输入位置留在原处(从当前偏移量中寻找零字节),除了可能会丢失由ungetc() 推回的字符。

与使用fseek()相比,使用fflush()是一种笨拙的操作方式。

使用套接字,单个文件描述符用于读取和写入远程方。但是,因为文件描述符函数没有缓冲,所以不会混淆如何处理已读取但尚未使用的数据(通过标准 I/O 流读取很容易发生),也不会混淆关于如何处理已写入 I/O 缓冲区但尚未发送到远程的数据。此外,与磁盘文件不同,套接字不是可查找的设备。管道、FIFO、终端和许多其他非磁盘、非磁带设备也是不可查找的。这并不能免除您遵守规则的责任,但可更新的流通常适用于磁盘等设备,您可以在其中读回您所写的内容,而对于不可搜索的设备则不然。

因此,如果您确实需要用于套接字 I/O 的文件流,您可能确实希望使用两个单独的流,一个仅用于读取,一个仅用于写入。在 POSIX 系统上,您可以使用 dup()dup2() 创建套接字文件描述符的副本,然后使用 fdopen() 两次创建读取和写入流。

【讨论】:

  • 如果我正确理解您的答案,创建这些规则的关键因素是因为 缓冲区,例如 fopen 打开一个缓冲的标准 I/O 流。所以对于无缓冲的流,无需担心。
  • @Rick:标准没有对无缓冲流给予任何豁免。做它说你必须做的事情。
猜你喜欢
  • 1970-01-01
  • 2016-04-27
  • 2021-07-07
  • 1970-01-01
  • 2017-04-26
  • 2015-12-31
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
相关资源
最近更新 更多