C 语言中 int fpurge() 和 int fflush() 的区别

6
有人能向我解释C语言中fpurge(FILE *stream)fflush(FILE *stream)的区别吗? fflush()fpurge()都会丢弃缓冲区中未写入或未读取的数据。 请解释一下这两者的确切区别,以及它们的优缺点。

从Linux手册页面fpurge()来看,fpurge()的一个问题是它是非标准的,源自BSD 4.4,因此不是在所有地方都可用。Mac OS X(BSD)的man页面描述了fpurge(),但没有提到它的起源 - 虽然它确实说fseek()与同一页上的列表符合标准C,所以(通过推断)fpurge()不符合标准C。 - Jonathan Leffler
2个回答

4
"...无论是fflush还是fpurge都会丢弃缓冲区中未写入或未读取的数据..." :不。
  • fflush

    fflush函数通过流的底层写函数,强制写入给定输出或更新流的所有缓冲数据。流的打开状态不受影响。 如果流参数为NULL,则fflush会刷新所有打开的输出流。

  • fpurge

    fpurge函数擦除了给定流中的任何输入或输出缓冲。对于输出流,这会丢弃任何未写入的输出。对于输入流,这会丢弃从底层对象读取但尚未通过getc获取的任何输入。这包括通过ungetc推回的任何文本。(P.S.:还存在__fpurge,它执行相同的操作,但不返回任何值)。

除了显而易见的缓冲数据效果外,你会注意到一个使用差异在于输入流。您可以清除此类流的fpurge(尽管通常是错误的,可能是概念上的)。根据环境,您可能不会fflush输入流(其行为可能是未定义的,请参见man page)。除了上述标记的区别外:1)导致错误的情况不同,2)如上所述,fflush可以在单个语句中处理所有输出流(这可能非常有用)。

至于优缺点,我不会真正引用任何...它们只是工作方式不同(主要是),因此您应该知道何时使用每个。

除了功能差异(您所问的),还存在可移植性差异:fflush是一个标准函数,而fpurge不是(而__fpurge也不是)。

这里是各自的手册页(fflushfpurge)。


2
首先,两个函数都会清除缓冲区(下面讨论可操作缓冲区的类型),主要区别在于缓冲区中存在的数据会发生什么。
  • 对于 fflush(),数据被强制写入磁盘
  • 对于 fpurge(),数据被丢弃

话虽如此,fflush()是标准的C函数,在《C11》第§7.21.5.2章中有提到。

fpurge()则是一个非便携和非标准的函数。从man page中可以看出:

这些函数是非标准的,不便携的。函数fpurge()是在4.4BSD中引入的,在Linux下不可用。函数__fpurge()是在Solaris中引入的,并在glibc 2.1.95及更高版本中存在。

话虽如此,使用方面的主要区别是:
  • 使用输入流调用 fflush()未定义行为

    如果 stream 指向最近一次操作不是输入的输出流或更新流,则 fflush 函数会导致该流的任何未写入数据被传递到主机环境以写入文件;否则,行为是未定义的。

  • 使用输入流调用 fpurge() 是已定义的。

    对于输入流,这将丢弃从底层对象读取但尚未通过 getc(3) 获得的任何输入;这包括通过 ungetc(3) 推回的任何文本。

不过,还是尽量坚持使用 fflush()

2
ISO C 可能未定义对输入流的 fflush,但 POSIX 规范中有说明。它的效果类似于 fpurge,只不过它仅适用于 可定位 的输入流,即可用于确保磁盘文件中没有缓冲的旧数据,但无法丢弃从管道或 tty 缓冲的数据。 - hobbs
@hobbs 对的,但是它仍然是实现定义的。 - Sourav Ghosh
我的意思是说,fflush(stdin) 的适用性。如果我没记错的话,MSVC 定义了它,但是带有这行代码的程序肯定不是_容易_可移植的。 :) - Sourav Ghosh
使用输入流调用fflush()是未定义的行为。而"使用输入流调用fpurge()是已定义的行为"则不一致。根据C标准,fflush(file_in_input_mode)是UB,而fpurge()也没有定义行为,因为它不在标准中。这两个函数在Linux和其他平台上都有定义。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接