在 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);
}