【问题标题】:what is the different of using fflush(stdout) and not using it使用 fflush(stdout) 和不使用它有什么不同
【发布时间】:2021-10-14 21:31:54
【问题描述】:
#include <stdio.h>

int main()
{
   printf("Hello");
   fflush(stdout);
   return 0;
}
#include <stdio.h>

int main()
{
   printf("Hello");
   return 0;
}

我正在尝试了解 fflush(stdout) 的用法,以及上面 2 个程序之间的区别是什么?

【问题讨论】:

  • stdout 将在程序终止时刷新,因此,在这种情况下,您不会注意到两个程序之间的任何差异。 fflush(stdout) 在这里是多余的。
  • 但是,如果您在 printffflush 之间添加一个明显的延迟,那么您会看到差异。
  • @JohnBollinger 我会说“如果你在两个程序中的return 0; 之前放置一个明显的延迟......”
  • 这也行,@TedLyngmo。
  • 这能回答你的问题吗? Flushing buffers in C

标签: c fflush


【解决方案1】:

stdout 指向一个tty 时,默认情况下它是line-buffered。这意味着输出会在计算机内部中缓冲,直到接收到(并输出)整行。

您的程序不会向计算机内部发送整行。

在使用fflush() 的情况下,您是在告诉计算机内部将缓冲区中的当前数据发送到设备;如果没有fflush(),您将依赖计算机内部在程序终止时为您执行此操作。

计算机内部我的意思是 C 库、操作系统、硬件接口、各种接口之间的(自动)缓冲区的组合,...

【讨论】:

  • 没有。不。不!!!默认情况下,输出到 tty 是行缓冲的。默认情况下,输出到常规文件是块缓冲的。不要将标准输出与 tty 混为一谈。
  • @Kain: $ executablestdout 使用tty ... $ executable &gt;file.txtstdout 使用文件
  • 其实不是操作系统,是c库。可能还有一个操作系统级别的缓冲区,它与来自FILE * 的缓冲区无关。
  • @pmg 在fflush() 之后,C-Library 持有的所有写入数据都被写入操作系统。所以你对 computer internals 的描述结合上面的文字是误导性的。 fflush() 的目的是将 C-Library 中的数据提供给底层系统(很可能是操作系统)。
  • @Kain No. stdout 和 tty 是一回事。认为它们是一个常见的错误是,你必须从你的内在心灵中消除这种基本的误解。如果从 shell 运行命令,则 shell 的标准输出将由命令继承。如果 shell 的 stdout 恰好与 tty 相关联(交互式 shell 经常出现这种情况),那么进程的 stdout 将转到 tty。但它们是一回事。
【解决方案2】:

在现代操作系统上运行的普通 C 程序中,文件访问被缓冲两次(当您计算像驱动器中的缓冲区这样的缓冲区时,或更多)。一个缓冲区在FILE 结构中实现,另一个在内核中实现。

通常,FILE 结构将内容缓冲在程序内部的缓冲区中。当您向缓冲文件写入内容时,内容将保存在正在运行的程序内部的缓冲区中。它在缓冲区已满时写入操作系统,当缓冲模式为行缓冲时,在行尾写入。该数据通过系统调用写入操作系统,例如write()。 缓冲区在那里是因为系统调用需要从用户程序到内核的上下文切换,这相对昂贵(慢),缓冲区在这里是为了减少系统调用的数量。您也可以直接使用程序中的系统调用而无需 stdio 函数,但是,此函数的可移植性较差且处理起来更复杂。 fflush(stdout) 检查缓冲区中是否有应写入的数据,如果有,则使用底层系统调用将数据写入操作系统。

当系统调用返回时,数据在您的内核中。但是现代操作系统也会缓冲这些数据。这用于减少磁盘写入次数,减少延迟和其他事情。这个缓冲区完全独立于程序中的FILE 缓冲区。

请注意,这并不适用于所有系统。例如,微控制器环境可能会提供一些 stdio.h 函数,它们直接写入 UART,没有任何缓冲区,既不在 FILE 内部,也没有任何(可能不存在的)操作系统。

要查看fflush() 对正在运行的程序的作用,请比较以下程序:

int main(void)
{
  fputs("s",stdout);
  fputs("e",stderr);
}

int main(void)
{
  fputs("s",stdout);
  fflush(stdout);
  fputs("e",stderr);
}

在 Linux 上,stderr 默认不缓存,所以fputs("e",stderr); 会立即打印数据。另一方面,fputs("s",stdout); 在 Linux 上默认为行缓冲,因此不会立即打印数据。这会导致第一个程序输出es 而不是se,但第二个程序输出se

您可以使用setvbuf()更改缓冲区模式

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 2021-11-29
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    相关资源
    最近更新 更多