缓冲区

该笔记适用于Ubuntu,在Windows或其他平台上可能会存在不同。

什么是缓冲

缓冲区又称为缓存,它是内存空间的一部分,用来缓冲输入或输出的数据。

为什么要引入缓冲区呢?

比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作远快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。

缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。

缓冲区的类型

缓冲区分为三种类型:全缓冲、行缓冲和不缓冲。

1、全缓冲

在这种情况下,当填满标准I/O缓存后才进行实际的I/O操作。全缓冲的典型代表是对磁盘文件的改写。

2、行输出

在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型的代表是键盘输入数据。

3、不缓冲

也就是不进行缓冲,标准出错情况stder是典型代表,这使得出错信息可以直接尽快地显示出来。

缓冲区的刷新

下列情况会引发缓冲区的刷新:

  1. 缓冲区满时;
  2. 执行fflush函数;
  3. 正常关闭文件;
  4. 正常退出程序或进程;
  5. 行缓冲遇到\n刷新。

如何改变缓存类型

这里只展示setvbuf函数的使用,定义流stream应如何缓冲。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//与缓冲区相关的一些函数
#include <stdio.h>
void setbuf(FILE *stream, char *buf);
void setbuffer(FILE *stream, char *buf, size_t size);
void setlinebuf(FILE *stream);


int setvbuf(FILE *stream, char *buf, int mode , size_t size);
参数:
stream:这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
buffer:这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
mode: 这指定了文件缓冲的模式:_IOFBF、_IOLBF、_IONBF。
size:这是缓冲的大小,以字节为单位。
返回值:
如果成功,则该函数返回 0,否则返回非零值。
模式 描述
_IOFBF 全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。
_IOLBF 行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。
_IONBF 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略,即在无缓存模式,即使设置了缓冲区也不会用到。

验证

先来对比VScode和Ubun中缓冲的表现形式

Vscode:

1.

2.

3.

4.

Ubuntu:
1.

2.

3.

4.

5.

6.

从以上10个测试可以得到结论:(不同平台不同的编译器得到的结果可能不一样)

  • VScode中的stdout属于无缓冲类型
  • Ubuntu中的stdout属于行缓冲类型(行缓冲遇到换行符会清空缓冲区,而全缓冲不会)

注意:缓冲区的大小选择1024(不管用默认的还是自己定义的)

验证setvbuf函数

  • 当缓冲区满的时候会刷新缓冲区

  • 当设为无缓冲区时,所设置的缓冲区会被忽略