伟明部落格

关于printf()函数不输出的问题

--发布于 2023-05-30 08:18:01

首先,看一个问题

#include <stdio.h>
#include <unistd.h> // sleep()函数的头文件
int main() {
    printf("hello world");
    sleep(5);
    return 0;
}

问题:对于上面的程序代码,hello world会在什么输出?

  • A. 会立刻输出
  • B. 在5秒后输出

答案是:B,hello world会在5秒后程序结束时才输出。

那为什么是5秒后才输出呢?那是因为我们使用的printf函数属于标准I/O库的函数,标准I/O库是带有缓冲功能的,目的是尽量减少read()write()系统调用的次数,提高性能。因为执行一次系统调用的性能消耗是比较高的。所以,标准I/O库的缓冲功能就是将这此输出攒起来,等积攒到一定程序后才真正地输出。

标准I/O提供了三种类型的缓冲:

  1. 全缓冲。这种缓冲区是输出到磁盘文件时才使用,它会等到缓冲区满了,才会进行真正的输出。
  2. 行缓冲。这种缓冲区的输出目的一般是屏幕终端,它一旦遇到了换行符后,就会进行真正的输出。这里我们可以注意到,上面的hello world后面是没有换行 符的,所以它会先攒起来。
  3. 不缓冲。标准出错流stderr就是不带缓冲的。一旦有什么错误信息,就立刻显示出来。

所以,可以总结一下:

  • 标准出错stderr是不带缓冲的。
  • 若是涉及终端设备(交互式设备),则它们是行缓冲的,否则是全缓冲的。

那么,如果我想立即输出怎么办?有3种方法。

方案1

既然输出到屏幕终端是行缓冲,那就将hello world后面加上换行符,即

printf("hello world\n");

方案2

使用setbuf()函数,关闭缓冲机制。此时代码变为

#include <stdio.h>
#include <unistd.h> 
int main() {
    setbuf(stdout, NULL); // 关闭标准输出stdout的缓冲机制
    printf("hello world");
    sleep(5);
    return 0;
}

方案3

使用fflush()函数强制输出缓冲区的内容。此时代码为

#include <stdio.h>
#include <unistd.h> 
int main() {
    printf("hello world");
    fflush(stdout); // 强制输出stdout的缓冲区的内容
    sleep(5);
    return 0;
}
--更新于 2023-06-08 09:31:58