Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1176753
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-03 13:28:16

       这里所说的缓冲区指的是为标准输入与标准输出设置的缓冲区,为什么要设置一个标准输入缓冲区主要是从效率上来考虑的,如果不设缓冲区会降低cpu的效率,因为它总是会等待用户输入完之后才会去执行某些指令!同样设置一个标准输出缓冲区是为了解决打印的问题!总之这样做的目的就是为了效率!

接下来讲解一下怎么设置标准输入与标准输出缓冲区。

如果我们不认为的设置的话,系统会自动的为标准输入与标准输入设置一个缓冲区,这个缓冲区的大小通常是4Kb的大小,这和计算机中的分页机制有关,因为进程在计算机中分配内存使用的就是分页与分段的机制,并且每个页的大小是4Kb,因此通常情况下缓冲区的大小会设置为4Kb的大小!并且这个缓冲区的类型是一个全缓冲的缓冲区!所谓全缓冲指的是:当缓冲区里的数据写满的时候(或者可以说达到顶端)缓冲区中的数据才会“写”到标准输入磁盘文件中,这里说的写不是将缓冲区中的数据移动到磁盘文件中,而是拷贝到磁盘文件中,也就说此时磁盘文件中保留了一份缓冲区内容的备份!除了全缓冲外还有不缓冲和行缓冲,不缓冲不太常见与常用,在这里我就不做讲解了!下面讲解一下什么是行缓冲。行缓冲指的是当在键盘上敲下回车键的时候数据会存储在缓冲区中,这是毫无疑问的,同时也将缓冲区的数据拷贝一份到磁盘文件中!那么磁盘文件中备份的内容有什么用呢??本人能力有限目前还没有发现有什么用!

当热我们还可以自己设置缓冲区,缓冲区的大小可以由我们自己决定,缓冲区的类型也由我们自己决定!在这里有两个函数,一个是setbuf( FILE *stream  , char*buffer  ) 另一个是setvbuf(FILE *stream  ,   char *buffer ,  int mode  ,  unsigned int  size  ) ;

其中缓冲区的类型可以是:_IOFBF :全缓冲  _IOLBF :行缓冲 _IONBF : 不缓冲

下面讲解一下缓冲区是怎么工作的!

当我们从键盘输入数据的时候数据并不是直接被我们得到(这个问题我在上面已经讲解过了,不在重复),而是将这些输入的数据放在了缓冲区中,然后我们从缓冲区中得到我们想要的数据!如果我们通过函数(setbuf , setvbuf)将缓冲区设置10个字节的大小,而我们从键盘输入了20个字节大小的数据,这样我们输入的前10个数据会放在缓冲区中,因为我们设置的缓冲区的大小只能够装下10个字节大小的数据,装不下20个字节大小的数据。那么剩下的那10个字节大小的数据怎么办呢??暂时放在了输入流中!

在C语言方式下 是一个结构体数组 _iobuf 类型是FILE结构体

struct _iobuf {

       char *_ptr;

       int   _cnt;

       char *_base;

       int   _flag;

       int   _file;

       int   _charbuf;

       int   _bufsiz;

       char *_tmpfname;

       };

结构体中的成员简单的介绍下

_ptr    //指向当前缓冲区内容的指针

_cnt    //如果是输入缓冲区  那他就是显示现在缓冲区里还有多少个有效数据

_base   //缓冲区基地址

_flag   //标志位   具体好像就是什么可写啊 可读啊之类的

_file   //这个是设备句柄(也可以说是文件句柄)

_bufsiz //缓冲区总大小   一般都是0x1000    也就是4k   也就是一个分页


在上面我们向缓冲区中放入了10个字节大小的数据,FILE结构体中的_cnt变为了10 ,说明此时缓冲区中有10个字节大小的数据可以读,同时我们假设缓冲区的基地址也就是_base是0x00428e60 ,它是不变的 ,而此时_ptr的值也为0x00428e60 ,表示从0x00428e60这个位置开始读取数据,当我们从缓冲区中读取5个数据的时候,_cnt变为了5 ,表示缓冲区中还有5个数据可以读,_ptr则变为了0x00428e65表示下次应该从这个位置开始读取缓冲区中的数据,如果接下来我们再读取5个数据的时候,_cnt则变为了0 ,表示缓冲区中已经没有任何数据了,_ptr变为了0x00428e69表示下次应该从这个位置开始从缓冲区中读取数据,但是此时缓冲区中已经没有任何数据了,所以要将输入流中的剩下的那10个数据放进来,这样缓冲区中又有了10个数据,此时_cnt变为了10 ,注意了刚才我们讲到_ptr的值是0x00428e69 ,而当缓冲区中重新放进来数据的时候这个_ptr的值变为了0x00428e60 ,这是因为当缓冲区中没有任何数据的时候要将_ptr这个值进行一下刷新,使其指向缓冲区的基地址也就是0x00428e60这个值!因为下次要从这个位置开始读取数据!


在这里有点需要说明:当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会被转换为一个换行符\n,这个换行符\n也会被存储在缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而不是6。

缓冲区的刷新就是将指针_ptr变为缓冲区的基地址 ,同时_cnt的值变为0 ,因为缓冲区刷新后里面是没有数据的!

例子:

#define BufferSize 1024 // 合适的大小

typedef struct node {

    char*buffer;

   struct node *next;

}*linkList;


LinkList *InitList() {

   LinkList *head;

    head= (char *)malloc(size(node));

   head->next = NULL:

   return head;

}


void AddData(LinkList *head, char *data) { // 将新数据添加到表尾

   LinkList *p = head;

   LinkList *anode = (char *)malloc(size(node));

    anode->buffer= (char *)malloc(size(BufferSize));

   strncpy(anode->buffer,data,BufferSize);

   anode->next = NULL:

   while(p->next) p = p->next;

   p->next = anode;

}


void DealData(LinkList *head) {

   LinkList *p = head->next;

   if(p) {

       head->next = p->next;

       // p->buffer指向的数据待处理

       free(p->buffer); // 处理完毕,释放空间

       free(p);

    }

}


阅读(823) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~