为什么C标准没有定义fflush(stdin)的行为?

3
我理解fflush(stdin)会导致未定义的行为,因为fflush只对输出缓冲区进行了定义。
但是为什么呢? 有没有历史原因导致fflush没有定义输入缓冲区?
C++提供了清除标准输入缓冲区的方法cin.clear(),我不明白为什么C标准将其留为空白。

5
你希望fflush(stdin)的行为是清空输入缓冲区吗?在输出缓冲区上使用fflush几乎相反;是的,缓冲区被清除了,但这只是因为其中的数据已经被刷新到操作系统进行安全存储,而不是被丢弃。让fflush(stdin)表示“抛弃缓冲区中的任何内容”会让人感到困惑,特别是在管道/套接字上。它甚至没有特别有用的含义;输入缓冲区并不同于坐落在操作系统输入句柄上的任何内容,因此永远不清楚你到底要抛弃什么。 - ShadowRanger
Linux man pages和MSDN文档都允许调用输入流。 - dbush
5
cin.clear() 只是清除 cin 的错误标志,不会刷新任何内容。在 C 语言中,相当于 clearerr。也许你想到的是 cin.ignore()?但即使是这样,它也只是一个高级的 fread - Miles Budnek
您使用的终端/控制台已经缓冲输入,除非按下回车键,否则您看不到任何内容。就像上世纪70年代电传打字机的工作方式。fflush() 无法清除终端缓冲区,因此通常不起作用。你的情况可能会有所不同。 - Hans Passant
MSDN文档中,“fflush on input stream是C标准的扩展”,这与策略的第二步是一致的。由于在C中调用fflush(stdin)是未定义行为,因此它允许该扩展而不是认可它。 - chux - Reinstate Monica
显示剩余4条评论
2个回答

8

为什么需要定义 fflush(stdin)?从程序的角度来看,缓冲区是透明的,因此 fflush(stdin) 可能不会丢弃任何内容,也可能会消耗并丢弃整个输入数据流。与输出流不同,在输出流中,程序控制已发出的内容,而程序不知道输入缓冲区中有什么。

fflush(stdin) 的结果最好是不确定的 - 没有清晰的方法可以说明它将做什么。在非终端行缓冲模式下的输入流上尝试它,并在指定其行为的平台上更改缓冲区的大小,然后再次尝试。您很可能会在随后读取的数据中获得完全不同的结果。


只需要尝试在一个指定其行为的平台上,使用非终端的输入流以行缓冲模式运行它。然后更改缓冲区大小并再次尝试即可。我无法弄清楚该如何测试它的行为。请问应该怎么做? - suhdonghwi

3
与普遍认为的不同,fflush(stdin)应该做什么并不清楚:
  • 一些程序员似乎认为它应该丢弃终端中的任何未决输入,在某些系统上确实是这样。
  • 其他人希望它只是丢弃通过ungetc()推回的字节,实际上一些系统就是这样实现的。
  • 仍有其他人期望其他内容,一些实现会有另一种行为,例如读取和丢弃所有可用的输入,包括来自常规文件的输入。
当一个函数在各种历史平台上以不兼容的方式实现时,C标准的理由似乎并没有试图指定任何内容,因为这将使许多现有平台不符合规范。因此,fflush(stdin)被指定为具有未定义的行为
请注意,最常期望的语义很容易实现为一个函数:
/* discard the rest of a line of pending input,
 * return EOF at end of file.
 */
int flushline(FILE *fp) {
    int c;
    while ((c = getc(fp)) != EOF && c != '\n')
        continue;
    return c;
}

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