C/C++的全缓冲、行缓冲和无缓冲

 更新时间:2020年08月12日 10:44:37   作者:Dabelv  
这篇文章主要介绍了C/C++的全缓冲、行缓冲和无缓冲的相关知识,帮助大家更好的理解和学习c/c++,感兴趣的朋友可以了解下

1.简介

C/C++中,基于I/O流的操作最终会调用系统接口read()和write()完成I/O操作。为了使程序的运行效率最高,流对象通常会提供缓冲区,以减少调用系统I/O接口的调用次数。

缓冲方式存在三种,分别是:
 (1)全缓冲。输入或输出缓冲区被填满,会进行实际I/O操作。其他情况,如强制刷新、进程结束也会进行实际I/O操作。

对于读操作来说,当读入内容的字节数等于缓冲区大小或者文件已经到达结尾,或者强制刷新,会进行实际的I/O操作,将外存文件内容读入缓冲区;对于写操作来说,当缓冲区被填满或者强制刷新,会进行实际的I/O操作,缓冲区内容写到外存文件中。磁盘文件操作通常是全缓冲的。

(2)行缓冲。输入或输出缓冲区遇到换行符会进行实际I/O操作。其他与全缓冲相同。

(3)无缓冲。没有缓冲区,数据会立即读入内存或者输出到外存文件和设备上。标准错误输出stderr是无缓冲的,这样能够保证错误信息及时反馈给用户,供用户排除错误。

三种缓冲类型的宏定义在头文件<stdio.h>

缓冲类型
全缓冲 _IOFBF
行缓冲 _IOLBF
无缓冲 _IONBF

Linux环境下,下面一段代码可以很好地体现全缓冲和行缓冲的区别。

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

int glob=6; 
int main(int argc, char** argv)
{
  int var; 
  pid_t pid; 
  printf("a write to stdout\n"); 
  if(pid=fork()<0)
  { 
    printf("fork error"); 
  }
  else
  { 
    if(pid==0)
    { 
      glob++; 
      var++; 
    } 
    else
    { 
      sleep(2); 
    } 
  } 
  printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var); 
  exit(0); 
}

编译成功后默认生成a.out,运行结果如下:

./a.out
a write to stdout
pid=4823,glob=7,var=4195873
pid=4824,glob=7,var=4195873

./a.out > temp.txt
cat temp.txt
a write to stdout
pid=4864,glob=7,var=4195873
a write to stdout
pid=4865,glob=7,var=4195873

可见printf在输出到标准输出(显示器)时,是行缓冲,遇到换行符时会将缓冲区内容输出到显示器,并清空缓冲区。当使用重定向命令时,标准输出被重定向到磁盘文件,此时标准输出变成全缓冲,遇到换行符不输出,而是被拷贝至子进程中,在父子进程结束后,各有一份输出。

2.缓冲区的设置

(1)缓冲打开或关闭,可使用函数setbuf()或者setbuffer()。参数buf指向缓冲区,表示开启缓冲,通常是全缓冲。将buf参数设置为NULL,表示关闭缓冲。注意,setbuffer()是非C标准库函数,常见于Linux。

setbuf()的缓冲区长度至少为BUFSIZ(定义在stdio.h),否则可能会出现缓冲区溢出。setbuffer可以指定缓冲区大小。

//@header:stdio.h
//@brief:设置指定的缓冲区或关闭缓冲
//@param:stream:文件指针;buffer:缓冲区地址
//@notice:使用默认缓冲大小BUFSIZ(在stdio.h中定义)
void setbuf ( FILE * stream, char * buffer );

//@notice:同setbuf,但可指定缓冲区大小
void setbuffer(FILE *stream, char *buf, size_t size);

将buffer指定为NULL,关闭标准输出缓冲。

setbuf(stdout,NULL)

指定新的缓冲区。

static char newBuffer[BUFSIZ];//至少是BUFSIZ(定义在stdio.h),否则存在缓冲溢出可能
setbuf(stdout,(char*)&newBuffer);

//或者指定缓冲区大小
static char newBuffer[512];
setbuffer(stdout,(char*)&newBuffer,512);

 (2)更改缓冲模式,可使用函数setvbuf()。

//@header:stdio.h
//@brief:更改缓冲模式并设置缓冲区
//@param:stream:文件指针;buf缓冲区地址;type:缓冲区模式;size:缓冲区大小
//@ret:0成功,非0失败
int setvbuf(FILE *stream, char *buf, int type, unsigned size);

例如,将流缓冲区设置为行缓冲,调用setvbuf()时,缓冲区地址设为NULL,缓冲区大小设为0。注意,前提是存在缓冲区。

setvbuf(stream,NULL,_IOLBF,0); //将缓冲改为行缓冲

//上面的代码等价于
setlinebuf(stream);       //for Linux

如果调用setvbuf指定了缓冲区大小size大于0,缓冲区buf为NULL,则交由setvbuf进行malloc申请缓冲区。

//间接申请1024字节全缓冲区
setvbuf(stream,NULL,_IOFBF,1024);

以上就是C/C++的全缓冲、行缓冲和无缓冲的详细内容,更多关于C/C++ 缓冲的资料请关注脚本之家其它相关文章!

相关文章

  • C++数据结构之并查集详解

    C++数据结构之并查集详解

    这篇文章主要介绍了C++数据结构之并查集详解,并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题,并查集的思想是用一个数组表示了整片森林,需要的朋友可以参考下
    2023-08-08
  • Opencv分水岭算法学习

    Opencv分水岭算法学习

    这篇文章主要为大家详细介绍了Opencv分水岭算法的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • C++之友元:友元函数和友元类详解

    C++之友元:友元函数和友元类详解

    友元是一种允许非类成员函数访问类的非公有成员的一种机制。可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元
    2013-09-09
  • OpenCV实现拼图算法

    OpenCV实现拼图算法

    这篇文章主要为大家详细介绍了OpenCV实现拼图算法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C语言double和float 实例分析

    C语言double和float 实例分析

    本文主要介绍了C语言中的浮点数(float,double),并通过实例代码进行分析比较,希望能帮助学习相关知识的同学
    2016-07-07
  • C++中4种类型转换的方法分享

    C++中4种类型转换的方法分享

    这篇文章主要为大家详细介绍了C++中4种类型转换的方法,文中的示例代码讲解详细,对我们学习C++有一定的帮助,感兴趣的可以了解一下
    2023-04-04
  • C++版本简易Flappy bird

    C++版本简易Flappy bird

    这篇文章主要介绍了C++版本简易Flappy bird的相关资料,需要的朋友可以参考下
    2015-03-03
  • opencv3/C++实现霍夫圆/直线检测

    opencv3/C++实现霍夫圆/直线检测

    今天小编就为大家分享一篇opencv3/C++实现霍夫圆/直线检测,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • C++简明图解分析浅拷贝与深拷贝

    C++简明图解分析浅拷贝与深拷贝

    在c++中,深拷贝和浅拷贝也算是一个难点,特别是对于初学者来说,往往在不知道两者区别的情况下而错误的使用了浅拷贝,从而导致了野指针之类的问题,但是又因为缺少理解所以很难定位到问题所在
    2022-06-06
  • c++基础使用STL的注意点详解

    c++基础使用STL的注意点详解

    这篇文章主要为大家介绍了c++基础使用STL的注意点,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12

最新评论