前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >认真理一理这些奇怪缓冲问题

认真理一理这些奇怪缓冲问题

作者头像
C语言与CPP编程
发布2020-12-02 11:48:51
1K0
发布2020-12-02 11:48:51
举报
文章被收录于专栏:c语言与cpp编程c语言与cpp编程

上一篇《不可不知的Linux中三种缓冲模式》中说到了三种缓冲类型,这一篇主要讲与缓冲相关的函数,这些函数可以修改默认的缓冲类型,及在实际中可能遇到的问题。

与缓冲相关的函数

我们知道标准错误永远是无缓冲的。当标准输入输出指向的是交互式设备(如终端)的时候,它们是行缓冲的。若不是则是全缓冲的。 那么这些默认的缓冲类型如何修改?其实可以通过这些函数修改:

代码语言:javascript
复制
#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 *类型,文件指针 buf 缓冲区指针 mode 缓冲模式,包括_IOFBF(全缓冲),_IOLBF(行缓冲),_IONBF(不带缓冲) size 缓冲区大小

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

代码语言:javascript
复制
void setbuf ( FILE * stream, char * buffer );

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

使用setbuf函数打开或者关闭缓冲,当buf是一个有效缓冲区时,此时缓冲打开,若流指向的是终端设备,则此时该流是行缓冲的,否则该流是全缓冲的;当buf为NULL的时候,表示关闭该缓冲。

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

代码语言:javascript
复制
#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{

    setbuf(stdout,NULL);
    printf("程序猿编码");
    sleep();

    return ;
}

编译运行:

通过设置stdout(标准输出)的第二个参数为NULL,将其变成了不带缓冲,因此你运行后发现,printf的打印会立即显示在终端。

使用setvbuf可以精确的说明缓冲的类型,这里是使用mode来说明的,mode的值包括以下几个

_IOFBF 全缓冲 _IOLBUF 行缓冲 _IONBUF 无缓冲

如果指定一个不带缓冲的流,则忽略buf和size参数。如果指定缓冲,则buf和size分别指定一个缓冲区域和缓冲区域的长度。若此时buf为NULL,则标准IO库将自动制定一个适合长度的缓冲区。

代码语言:javascript
复制
#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{

    setvbuf(stdout,NULL,_IONBF,);
    printf("程序猿编码");
    sleep();

    return ;
}

编译运行:

设置为不带缓冲

标准I/O库不进行任何字符缓冲,任何读写都是即时可见的。linux下标准错误输出默认是不缓冲,来看一个例子:

代码语言:javascript
复制
#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{

    //setbuf(stdout,NULL);
    fputs("hello", stderr);
    sleep();
    fputs("程序猿编码", stderr);
    sleep();

    return ;
}

编译运行:

编译执行上面的程序,结果就比较显而易见了。程序一执行的时候就会输出”hello“,过两秒输出”程序猿编码“,再过两秒程序就结束了。 在C语言中,可以通过setbuf来设定无缓冲模式,只要将第二个参数设置为NULL就可以了; 也可以通过setvbuf来设定无缓冲模式,其中_IONBF表示行缓冲,就是IO not buffer的意思。 printf打印的日志没有输出 不知道你有没有遇到过这样的情况,准备调试某一个bug,发现每次运行到某个地方,打印就结束了,然后就挂了,让你误以为程序执行到打印的地方就结束了。 然而有可能程序执行到后面,只是由于打印是行缓冲的,导致部分打印没有出来,很可能就是你没有加上换行符打印而已。 这时候你可以设置为不带缓冲,或者关键位置fflush,或者打印记得加上换行符。 当然你还可以用GDB《GDB调试入门,看这篇就够了!》 控制文件I/O的内核缓冲 在某些情况下,我们可能需要强制将内核缓冲区内的数据刷新至磁盘,而不必等待内核线程等待特定时间后才写入。此时主要有两种选择

1、使用fsync,fdatasync, sync系统调用中的某一个将内核缓冲区的数据强制写入磁盘 2、以O_SYNC同步方式调用open打开文件,此后每次读写操作都会自动立即写入磁盘

代码语言:javascript
复制
#include <unistd.h>

int fsync(int fd);
int fdatasync(int fd);
void sync(void);

fsync保证同步I/O文件完整性,fdatasync保证同步I/O数据完整性。 两个完整性的区别在于前者会将所有更新的文件元数据写入磁盘,后者不会传递所有经过修改的文件元数据属性(如:时间戳)。 fsync与fdatasync均是刷新指定文件流数据,而sync()函数会更新所有内核缓冲区数据至磁盘,对应shell指令sync。

参考:《Linux/UNIX系统编程手册》

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 C语言与CPP编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 与缓冲相关的函数
  • 设置为不带缓冲
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档