在 C 语言刷新 stdout 输出流

Jinku Hu 2023年10月12日
  1. 在 C 语言中使用 fflush 函数来刷新 stdout 输出流
  2. 在 C 语言中使用 printf 函数演示 fflush 行为
在 C 语言刷新 stdout 输出流

本文将演示关于如何在 C 语言中刷新 stdout 输出流的多种方法。

在 C 语言中使用 fflush 函数来刷新 stdout 输出流

C 标准库提供了一个 I/O 库,即 stdio,它基本上代表了在用户空间中进行的 I/O 操作的缓冲版本,从而提高了常见用例的性能。一般来说,访问文件和对文件进行操作是由操作系统服务提供的,因此,用户最终需要系统调用,例如打开一个文件。频繁的系统调用会使程序的运行速度变慢,因为它需要访问操作系统的内核数据结构并来回传输控制。因此,在使用 stdio 函数调用时,C 库会维护一些缓冲区来处理输入/输出操作。

如果用户需要对内核缓冲区进行强制写入,则需要对 fflush 函数提供的给定流进行刷新。fflush 需要一个 FILE 的单参数,指向给定流的指针。请注意,fflush 对输出流强制执行写功能,同时丢弃输入流的任何缓冲数据(有可寻文件)。如果参数是 NULL,它将刷新所有打开的输出流。

注意,fflush 并不能确保写入的数据被物理存储,因为这需要内核缓冲区被刷新(可以使用 fsync 调用来完成,请参见这里)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  char *username;
  size_t len;
  int lnmax = 256;

  username = malloc(lnmax);
  if (username == NULL) perror("malloc");

  printf("Username: ");
  fflush(stdout);
  if (fgets(username, lnmax, stdin) == NULL) exit(EXIT_FAILURE);

  printf("Your username is set to - %s", username);

  exit(EXIT_SUCCESS);
}

输出:

Username: tmp
Your username is set to - tmp

在 C 语言中使用 printf 函数演示 fflush 行为

请注意,有些流(如 stderr)是没有缓冲的。相反,隐含写入 stdout 流的 printf 函数是有缓冲的,如果我们在下面执行每次迭代打印一个字符的无限循环,直到内部缓冲区满了才会向流输出内容。因此,下面的代码示例的结果是突发打印 bullet 字符。请注意,我们每次迭代都调用 usleep 函数,以减慢人眼的执行速度,以便于清晰地观察到。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  while (1) {
    printf(".");
    usleep(1e3);
  }

  exit(EXIT_SUCCESS);
}

另外,如果我们用 fprintf 代替 printf 的调用,打印到 stderr 流,就会产生每秒钟一个字符的迭代打印行为。再次强调,每次迭代的 1 秒延迟只是为了保证良好的演示效果。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  while (1) {
    fprintf(stderr, ".");
    sleep(1);
  }

  exit(EXIT_SUCCESS);
}

最后,如果我们需要在 stdout 流上模仿前面示例代码中看到的相同行为,我们可以在 printf 函数后添加 fflush 调用。这将迫使 C 库缓冲区在每次迭代时写入内核缓冲区,从而产生类似的行为。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  while (1) {
    printf(".");
    fflush(stdout);
    sleep(1);
  }

  exit(EXIT_SUCCESS);
}
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook

相关文章 - C IO