fflush(stdin) 在 C 编程中有啥作用? [复制]

Posted

技术标签:

【中文标题】fflush(stdin) 在 C 编程中有啥作用? [复制]【英文标题】:What does fflush(stdin) do in C programing? [duplicate]fflush(stdin) 在 C 编程中有什么作用? [复制] 【发布时间】:2014-05-19 01:48:23 【问题描述】:

我对 C 编程非常陌生,我正在尝试了解 fflush(stdin) 的真正工作原理。

在以下示例中,fflush(stdin) 是清除所有缓冲区还是清除第三项之后输入的任何内容?我的意思是用户输入帐号、空格、姓名、空格、余额。从现在开始,用户输入的任何内容都会被fflush(stdin) 刷新,这是真的吗? stdin 不会为空。

为什么这么说是因为它进入了一个while循环并开始写入文本文件。

我的第二个问题是Ctrl-Z 是否会告诉操作系统停止要求用户输入输入?

printf( "Enter the account name and balance. (separated by spaces)\n" );
  printf( "Enter EOF to end input. (Ctrl-Z)\n" );
  printf( "? " );
  scanf( "%d%s%lf", &account, name, &balance );
  fflush(stdin);

  // write account, name and balance into file with fprintf
  while ( !feof( stdin ) )
   
     //fflush(stdin);
     fprintf( cfPtr, "%d %s %.2f\n", account, name, balance );
     printf( "? " );
     scanf( "%d%s%lf", &account, name, &balance );
  

  fclose( cfPtr );

【问题讨论】:

fflush(stdin); 是未定义的行为。不要这样做,不要从那些这样做的人那里复制它。 ***.com/questions/2979209/using-fflushstdin @chrk 不同意添加“linux”标签。 OP 的帖子中没有任何内容是特定于 Linux 的。 @chrk 是的还原。标签是针对帖子的主题,而不是针对寻找的人的类型。 【参考方案1】:

这个问题的答案是fflush(stream)只是为输出流正式定义的,所以fflush(stdout)可以,但fflush(stdin)不行。

fflush(stream) 的目的是让操作系统将所有缓冲区刷新到底层文件。以合法使用为例,学生经常会遇到“我的提示没有出现!”之类的问题。如果他们这样做:

printf("Enter a number: ");

但是,他们发现这很好用:

printf("Enter a number:\n");

当然,他们不想在提示后换行,所以他们有点问题。

原因是stdout 的输出由操作系统缓冲,默认行为(通常)仅在遇到换行符时实际将输出写入终端。在printf() 之后添加fflush(stdout) 即可解决问题:

printf("Enter a number: ");
fflush(stdout);

现在,打个比方,人们通常认为fflush(stdin) 应该丢弃任何未使用的输入,但如果您稍微考虑一下,这并没有多大意义。 “刷新”输入缓冲区是什么意思? 它在哪里“冲洗”?如果刷新输出缓冲区,则输出将发送到底层文件或终端,无论如何它最终都会结束,但是 input “最终还是会结束”?没有办法知道!如果输入流数据来自文件、管道或套接字,应该有什么行为? 根本不清楚输入流fflush() 的行为应该是什么,但在所有情况下对于输出流来说都非常清楚。因此,fflush() 仅为输出流定义。

fflush(stdin) 的错误使用变得司空见惯的原因是,许多年前,一些操作系统确实实施了一个方案,它可以像许多人预期的那样工作,丢弃未使用的输入。 Microsoft DOS 就是一个很好的例子。令人惊讶的是,现代版本的 Linux 还为输入流实现了​​ fflush()

处理“额外的”不需要的终端输入的正确做法是简单地阅读它而不用它做任何事情。这几乎就像调用 fflush(stdin) 一样简单,在任何地方都可以使用,并且不依赖于正式未定义的行为。

C 标准说:

如果 stream 指向输出流或更新流,其中没有输入最近的操作,则 fflush 函数会将该流的任何未写入数据传递到主机环境写入文件; 否则,行为未定义

POSIX says(也明确遵循 C 标准):

如果流指向输出流或更新流,其中没有输入最近的操作,fflush() 将导致该流的任何未写入数据写入文件,. ..

但是Linux manpage 说:

对于输出流,fflush() 通过流的底层写入函数强制写入给定输出或更新流的所有用户空间缓冲数据。 对于输入流,fflush() 会丢弃任何已从底层文件获取但尚未被应用程序使用的缓冲数据。流的打开状态不受影响。

【讨论】:

请注意,这(Linux 为其他未定义的行为提供定义)是一个特定于实现的扩展,对可移植代码感兴趣的人应该避免使用。class="comcopy">跨度> @Emmet 正如您提到的,您需要fflush(stdout);,但没有它它工作正常。你能给出缓冲区未满的特殊情况,所以printf 无法在屏幕上打印。 @Emmet 顺便说一句谢谢我忘了你对fflush(stdin) 的解释太棒了,只是解释清楚。【参考方案2】:

fflush(stdin) 调用未定义的行为。

fflush() 仅为输出流定义。你不应该这样做。


在 Unix 上,Ctrl-Z 发送一个 TSTP 信号 (SIGTSTP),默认情况下会导致进程暂停执行。

【讨论】:

以上是关于fflush(stdin) 在 C 编程中有啥作用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

解决linux下fflush(stdin)无效

fflush(stdin)和rewind(stdin)

ACM的fflush(stdin)的问题

搞懂 fflush(stdout)

如何在C中检查stdin是不是为空

文件中注释的字符数(C编程)