在 C 语言刷新 stdout 输出流

Jinku Hu 2023年1月30日 2021年2月28日
  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 <unistd.h>
#include <time.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);
}
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn

相关文章 - C IO