-
C语言环形buffer
2019-07-25 22:06:28C语言环形数组 这是一个循环缓冲区,终于写完了,指针指来指取还是很麻烦的,稍微不注意就出错了 但是思路还是挺简单的,不过对于小白的我还是用了蛮久的时间的,关键是开始没有构思好 所以出了很多问题,这是最终...C语言环形数组
-
这是一个循环缓冲区,终于写完了,指针指来指取还是很麻烦的,稍微不注意就出错了
但是思路还是挺简单的,不过对于小白的我还是用了蛮久的时间的,关键是开始没有构思好
所以出了很多问题,这是最终版本,以后希望对自己有用,今天是2019.7.25 大吉大利的晚上,各位加油 -
头文件
#include<stdio.h> #include <string.h>
- 函数声明和环形存储区的建立,环形结构体指针的声明
- 在这里我将以数组作为环形存储区的存储区域,在这里也可以用动态申请内存,这里设置的类型也是int 这里可以根据自己需要更改数据类型,或者定义为一个void *类型,函数的功能就更强大了,不够后面要强制转换,我是个小白,所以以比较简单的想法写的,
#define RB_MAX_LEN 10 typedef unsigned int uint_t; typedef struct { uint_t sizerb; int *write; int *read; int *buffer; uint_t rw;//0代表已经读 1代表已经写, }rb_t; rb_t rb; static uint_t rbBuf[RB_MAX_LEN]; void creatrb(rb_t* rb);
- 初始化一个环形存储区域
void buff_init(void) { rb.sizerb = RB_MAX_LEN; //定义长度 rb.buffer = rbBuf; //将申请的一个空间的首地址给buffer creatrb(&rb); //然后运行创建函数 }
- 创建一个环形存储区
void creatrb(rb_t* rb) { if(NULL == rb) //判断指针是否为空 { printf("fault\n"); return; } rb->write= rb->buffer; //将读和写都指向首地址,创建完毕 rb->read = rb->buffer; rb->rw =0; }
- 删除环形存储区
static void deleterb(rb_t *rb) { if(NULL == rb) { printf("error"); } rb->write = NULL; rb->read = NULL; rb->buffer= NULL; rb->sizerb = 0; rb->rw =0; }
- 获取存储区域大小
static uint_t getrb_capacity(rb_t *rb) { if(NULL == rb) //判断指针是否为空 { printf("fault\n"); return -1; } return rb->sizerb; }
- 获取存储区域可写字节的大小
static uint_t rbcanWrite(rb_t *rb) { if(NULL == rb) //判断指针是否为空 { printf("fault\n"); return -1; } if(rb->write >rb->read) { return getrb_capacity(rb)- (rb->write-rb->read); } else if((rb->write == rb->read)) { if(0 ==rb->rw) { return getrb_capacity(rb); } else { return 0; } }else if((rb->write < rb->read)) { return (rb->read - rb->write); } }
- 获取环形缓冲区可读字节的大小
static uint_t rbcanRead(rb_t *rb) { if(NULL == rb) //判断指针是否为空 { printf("fault can read\n"); return -1; } return getrb_capacity(rb)- rbcanWrite(rb); }
- 从环形存储区读取想要的数据个数
static uint_t rbRead(rb_t *rb,int *date,uint_t count) { int cpysz = 0,r_end=0; if(NULL == rb) //判断指针是否为空 { printf("fault\n"); return -1; } if(NULL == date) //判断被放地址是否为空 { printf("fault\n"); return -1; } if(0==rbcanRead(rb)) //如果地址相同,并且在起点,表示无法读取没有数据 { printf("fault\n"); return -1; } //开始读取数据 if(rb->write > rb->read) //读小余写 { if(count>((rb->write) - (rb->read))) cpysz = ((rb->write) - (rb->read)); else cpysz = count; memcpy(date,rb->read,cpysz*sizeof(int)); memset(rb->read,0,cpysz*sizeof(int)); rb->read += cpysz; return cpysz; } else //读大于余写 { r_end = rb->sizerb-(rb->read - rb->buffer); if(count>=rbcanRead(rb)) { cpysz = rbcanRead(rb); memcpy(date,rb->read,r_end*sizeof(int)); memset(rb->read,0,r_end*sizeof(int)); rb->rw=0; //表示读循环一次 rb->read = rb->buffer; //date是个空类型 memcpy(date+r_end,rb->read,(cpysz-r_end)*sizeof(int) ); memset(rb->read,0,(cpysz-r_end)*sizeof(int)); rb->read+=(cpysz-r_end); return cpysz; } else { cpysz = count; if(count < r_end) { memcpy(date,rb->read,count*sizeof(int)); memset(rb->read,0,count*sizeof(int)); rb->read+=cpysz; } else { memcpy(date,rb->read,r_end*sizeof(int)); memset(rb->read,0,r_end*sizeof(int)); rb->rw=0; //表示读循环一次 rb->read = rb->buffer; memcpy(date+r_end,rb->read,(count-r_end)*sizeof(int) ); memset(rb->read,0,(count-r_end)*sizeof(int)); rb->read+=(count-r_end); } return cpysz; } } }
- 向环形存储区写入数据
static uint_t rbWrite(rb_t *rb,int *date,uint_t count) { int cpysz = 0,r_end=0; if(NULL == rb) //判断指针是否为空 { printf("fault 1\n"); return -1; } if(NULL == date) //判断被放地址是否为空 { printf("fault 2\n"); return -1; } if(0==rbcanWrite(rb)) { printf("fault 3\n"); return -1; } if(rb->write < rb->read) //写小于读 { if(count>((rb -> read) - (rb->write))) { cpysz = rb->read -rb->write; } else { printf("write\n"); cpysz = count; } memcpy(rb->write,date,cpysz*sizeof(int)); rb->write+= cpysz; return cpysz; } else //写大于等于读 { r_end = rb->sizerb-(rb->write - rb->buffer); if(count > rbcanWrite(rb)) { cpysz = rbcanWrite(rb); memcpy(rb->write,date,r_end*sizeof(int)); rb->rw=1; //表示写循环一次 rb->write = rb->buffer; printf("mmp %d\n",r_end ); memcpy(rb->write,date+r_end,(cpysz-r_end)*sizeof(int) ); rb->write+=(rb->read-rb->buffer); return cpysz; } else { printf("this is write == \n\n\n"); cpysz = count; if(count < r_end) { memcpy(rb->write,date,count*sizeof(int)); rb->write +=count; } else if(count >= r_end) { memcpy(rb->write,date,r_end*sizeof(int)); rb->rw=1; //表示写循环一次 rb->write = rb->buffer;//rb->buffer printf("mmp %d\n",r_end ); memcpy(rb->write,date+r_end,(count-r_end)*sizeof(int) ); rb->write += (count-r_end); } return cpysz; } } }
- 主函书进行初始化和调试,验证是否正确
int main(void) { int i,a[50]={1,2,3,4,5,6,7,8,9,10,11},b[10]={0},a1[50]={99,88,77,66,55,22,33,22,11,00,82,54,56,22,1,346,45,15,15,1,6,26,15}; unsigned int mmp=0; buff_init(); //创建一个环形存储区 printf("开始创建环形缓冲区\n"); printf("环形存储空间大小为 %d\n",getrb_capacity(&rb)); printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); putchar('\n'); putchar('\n'); printf("准备给环形缓冲区内写入数据\n"); for(i=0;i<10;i++)printf("not write rbBuff[%d]= %d\n",i,rbBuf[i]); mmp=rbWrite(&rb,a,10); //写入五个数据 printf("成功写入 %d 个数据\n",mmp); printf("存储区域有自己数 = %d %d\n",sizeof(rbBuf),sizeof(size_t)); for(i=0;i<10;i++)printf("写完数据 rbBuf[%d]= %d\n",i,rbBuf[i]); putchar('\n'); putchar('\n'); printf("查看空间\n"); for(i=0;i<10;i++)printf("b[10] %d\n",*(b+i)); printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); putchar('\n'); putchar('\n'); printf("begain to read\n"); rbRead(&rb,b,3); //读取三个数据 printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); for(i=0;i<10;i++)printf("b[10] %d\n",*(b+i)); for(i=0;i<10;i++)printf("had write rbBuf[%d]= %d\n",i,rbBuf[i]); printf("再读数据\n"); rbRead(&rb,b,2); //读取两个数据 printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); for(i=0;i<10;i++)printf("b[10] %d\n",*(b+i)); for(i=0;i<10;i++)printf("had write rbBuf[%d]= %d\n",i,rbBuf[i]); printf("\n\n再写数据\n"); rbWrite(&rb,a1,20); //写入七个数据 printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); for(i=0;i<10;i++)printf("had write rbBuf[%d]= %d\n",i,rbBuf[i]); putchar('\n'); putchar('\n'); printf("后面加再读数据\n"); rbRead(&rb,b,11); //读取两个数据 printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); for(i=0;i<10;i++)printf("b[10] %d\n",*(b+i)); for(i=0;i<10;i++)printf("had write rbBuf[%d]= %d\n",i,rbBuf[i]); printf("canwrite %d\n",rbcanWrite(&rb)); printf("canRead %d\n",rbcanRead(&rb)); return 0; }
-
-
C语言 ringBuffer 实现
2020-04-24 22:36:04一、 ringBuffer 介绍 ringBuffer 称作环形缓冲,也有叫 circleBuffer 的。就是取内存中一块连续的区域用作环形缓冲区的数据存储区。这块连续的存储会被反复使用,向 ringBuffer 写入数据总是从写指针的位置开始,...一、 ringBuffer 介绍
ringBuffer 称作环形缓冲,也有叫 circleBuffer 的。就是取内存中一块连续的区域用作环形缓冲区的数据存储区。这块连续的存储会被反复使用,向 ringBuffer 写入数据总是从写指针的位置开始,如写到实际存储区的末尾还没有写完,则将剩余的数据从存储区的头开始写;从该 ringBuffer 读出数据也是从读指针的位置开始,如读到实际存储区的末尾还没有读完,则从存储区的头开始读剩下的数据。
为了保证写入的数据不会覆盖 ringBuffer 里还没有被读出的数据,以及读出的数据不是已经读出过的旧数据,需要使用一个变量 btoRead 表示该 ringBuffer 中有效的数据。使用变量 length 表示该环形缓冲区中真实的缓冲大小。使用指针 source 指向实际的缓存地址。
使用 ringBuffer 读写数据,要确保读写数据的速率和实际缓冲区大小的匹配。如果不匹配,可能会导致溢出,比如读数据太慢,而写数据很快,实际的缓存区又太小,导致整个缓冲区都是还没有被读出的数据,此时新的数据就无法写入。正确使用 ringBuffer 可以保证数据的连续,降低读模块和写模块之间的耦合性。更多关于生产者-消费者模型的知识可以看这篇博客。
二、代码
ringBuffer 的结构体
typedef struct { uint8_t *source; uint32_t br; uint32_t bw; uint32_t btoRead; uint32_t length; }ringbuffer_t;
创建 ringBuffer 函数
void create_ringBuffer(ringbuffer_t *ringBuf, uint8_t *buf, uint32_t buf_len) { ringBuf->br = 0; ringBuf->bw = 0; ringBuf->btoRead = 0; ringBuf->source = buf; ringBuf->length = buf_len; printf("create ringBuffer->length = %d\n", ringBuf->length); }
清空 ringBuffer 函数
void clear_ringBuffer(ringbuffer_t *ringBuf) { ringBuf->br = 0; ringBuf->bw = 0; ringBuf->btoRead = 0; //no need do this casue r_ptr and w_prt has change //memset((uint8_t *)ringBuf->source, 0, ringBuf->length); }
读数据函数
uint32_t write_ringBuffer(uint8_t *buffer, uint32_t size, ringbuffer_t *ringBuf) { uint32_t len = 0; uint32_t ringBuf_bw = ringBuf->bw; uint32_t ringBuf_len = ringBuf->length; uint8_t *ringBuf_source = ringBuf->source; if( (ringBuf_bw + size) <= ringBuf_len ) { memcpy(ringBuf_source + ringBuf_bw, bufff, size); } else { len = ringBuf_len - ringBuf_bw; memcpy(ringBuf_source + ringBuf_bw, buffer, len); memcpy(ringBuf_source, buffer + ringBuf_bw, size - len); } ringBuf->bw = (ringBuf->bw + size) % ringBuf_len; ringBuf->btoRead += size; return size; }
写数据函数
uint32_t read_ringBuffer(uint8_t *buffer, uint32_t size, ringbuffer_t *ringBuf) { uint32_t len = 0; uint32_t ringBuf_br = ringBuf->br; uint32_t ringBuf_len = ringBuf->length; uint8_t *ringBuf_source = ringBug->source; if( (ringBuf_br + size ) <= ringBuf_len ) { memcpy(buffer, ringBuf_source + ringBuf_br, size); } else { len = ringBuf_len - ringBuf_br; memcpy(bufff, ringBuf_source + ringBuf_br, len); memcpy(buffer + len, ringBuf_source, size - len); } ringBuf->br = (ringBuf->br + size) % ringBuf_len; ringBuf->btoRead -= size; return size; }
获取 ringBuffer 中的有效数据
uint32_t get_ringBuffer_btoRead(ringbuffer_t *ringBuf) { return ringBuf->btoRead; }
获取 ringBuffer 的长度
uint32_t get_ringBuffer_length(ringbuffer_t *ringBuf) { return ringBuf->length; }
三、使用方法
对 ringBuffer 的使用,首先需要又一块真实并且连续的数据存储区。可以使用 malloc 从堆区分配,也可以使用一个数组。
在写数据之前,需要对此时 ringBuffer 的剩余空间和要写入数据的大小进行比较。剩余空间使用长度 length 减去待读出数据量 btoRead 得到。
在读出数据之前,则需要对此时 ringBuffer 可读出的有效数据 btoRead 进行判断。
读出的数据不够,或者没有足够的空间写如数据,可以在调用读写函数之前进行判断,假如情况不满足,就不调用相应的读写函数。
-
c语言实现循环buffer
2019-01-08 18:32:54linux c语言实现的循环buffer机制,可以在多线程之间传递共享buffer队列 -
c ringbuffer 源码_C语言 ringBuffer 实现
2021-01-14 17:14:46一、 ringBuffer 介绍ringBuffer 称作环形缓冲,也有叫 circleBuffer 的。就是取内存中一块连续的区域用作环形缓冲区的数据存储区。这块连续的存储会被反复使用,向 ringBuffer 写入数据总是从写指针的位置开始,如...一、 ringBuffer 介绍
ringBuffer 称作环形缓冲,也有叫 circleBuffer 的。就是取内存中一块连续的区域用作环形缓冲区的数据存储区。这块连续的存储会被反复使用,向 ringBuffer 写入数据总是从写指针的位置开始,如写到实际存储区的末尾还没有写完,则将剩余的数据从存储区的头开始写;从该 ringBuffer 读出数据也是从读指针的位置开始,如读到实际存储区的末尾还没有读完,则从存储区的头开始读剩下的数据。
为了保证写入的数据不会覆盖 ringBuffer 里还没有被读出的数据,以及读出的数据不是已经读出过的旧数据,需要使用一个变量 btoRead 表示该 ringBuffer 中有效的数据。使用变量 length 表示该环形缓冲区中真实的缓冲大小。使用指针 source 指向实际的缓存地址。
使用 ringBuffer 读写数据,要确保读写数据的速率和实际缓冲区大小的匹配。如果不匹配,可能会导致溢出,比如读数据太慢,而写数据很快,实际的缓存区又太小,导致整个缓冲区都是还没有被读出的数据,此时新的数据就无法写入。正确使用 ringBuffer 可以保证数据的连续,降低读模块和写模块之间的耦合性。更多关于生产者-消费者模型的知识可以看这篇博客。
二、代码
ringBuffer 的结构体
typedef struct {
uint8_t *source;
uint32_t br;
uint32_t bw;
uint32_t btoRead;
uint32_t length;
}ringbuffer_t;
创建 ringBuffer 函数
void create_ringBuffer(ringbuffer_t *ringBuf, uint8_t *buf, uint32_t buf_len)
{
ringBuf->br = 0;
ringBuf->bw = 0;
ringBuf->btoRead = 0;
ringBuf->source = buf;
ringBuf->length = buf_len;
printf("create ringBuffer->length = %d\n", ringBuf->length);
}
清空 ringBuffer 函数
void clear_ringBuffer(ringbuffer_t *ringBuf)
{
ringBuf->br = 0;
ringBuf->bw = 0;
ringBuf->btoRead = 0;
//no need do this casue r_ptr and w_prt has change
// memset((uint8_t *)ringBuf->source, 0, ringBuf->length);
}
读数据函数
uint32_t write_ringBuffer(uint8_t *buffer, uint32_t size, ringbuffer_t *ringBuf)
{
uint32_t len = 0;
uint32_t ringBuf_bw = ringBuf->bw;
uint32_t ringBuf_len = ringBuf->length;
uint8_t *ringBuf_source = ringBuf->source;
if( (ringBuf_bw + size) <= ringBuf_len )
{
memcpy(ringBuf_source + ringBuf_bw, bufff, size);
}
else
{
len = ringBuf_len - ringBuf_bw;
memcpy(ringBuf_source + ringBuf_bw, buffer, len);
memcpy(ringBuf_source, buffer + ringBuf_bw, size - len);
}
ringBuf->bw = (ringBuf->bw + size) % ringBuf_len;
ringBuf->btoRead += size;
return size;
}
写数据函数
uint32_t read_ringBuffer(uint8_t *buffer, uint32_t size, ringbuffer_t *ringBuf)
{
uint32_t len = 0;
uint32_t ringBuf_br = ringBuf->br;
uint32_t ringBuf_len = ringBuf->length;
uint8_t *ringBuf_source = ringBug->source;
if( (ringBuf_br + size ) <= ringBuf_len )
{
memcpy(buffer, ringBuf_source + ringBuf_br, size);
}
else
{
len = ringBuf_len - ringBuf_br;
memcpy(bufff, ringBuf_source + ringBuf_br, len);
memcpy(buffer + len, ringBuf_source, size - len);
}
ringBuf->br = (ringBuf->br + size) % ringBuf_len;
ringBuf->btoRead -= size;
return size;
}
获取 ringBuffer 中的有效数据
uint32_t get_ringBuffer_btoRead(ringbuffer_t *ringBuf)
{
return ringBuf->btoRead;
}
获取 ringBuffer 的长度
uint32_t get_ringBuffer_length(ringbuffer_t *ringBuf)
{
return ringBuf->length;
}
三、使用方法
对 ringBuffer 的使用,首先需要又一块真实并且连续的数据存储区。可以使用 malloc 从堆区分配,也可以使用一个数组。
在写数据之前,需要对此时 ringBuffer 的剩余空间和要写入数据的大小进行比较。剩余空间使用长度 length 减去待读出数据量 btoRead 得到。
在读出数据之前,则需要对此时 ringBuffer 可读出的有效数据 btoRead 进行判断。
读出的数据不够,或者没有足够的空间写如数据,可以在调用读写函数之前进行判断,假如情况不满足,就不调用相应的读写函数。
-
C语言 FileStreaming buffer
2020-01-01 12:34:44void setbuf ( FILE * stream, char * buffer ); Set stream buffer 设置文件描述符的缓冲区大小 stream buffer是一个 block of data,在i/o操作和 physical file(文件) 之间 output buffers,写出:数据会放在buffer...setbuf
void setbuf ( FILE * stream, char * buffer );
Set stream buffer- 设置文件描述符的缓冲区大小
- stream buffer是一个 block of data,在i/o操作和 physical file(文件) 之间
- output buffers,写出:数据会放在buffer区,直到填满,然后会flushed(发送给 物理文件并清空buffer区)
- input buffers,也是如此
- Stream buffers can be explicitly flushed by calling
fflush
,fclose
andfreopen
或者程序terminates normally(正常终止)会自动调用fllush
- 所有打开的文件都默认带有
buffer
- stdin and stdout are fully buffered by default if they are known to not refer to an interactive . Otherwise, they may either be line buffered or unbuffered by default
- 通过setvbuf 改变缓冲方式
参数 描述 stream FILE object buffer 存放buffer的数组 #pragma warning(disable:4996) #include<stdio.h> #include<stdlib.h> int main() { char buf[BUFSIZ]; printf("缓冲区大小是%d字节\n", BUFSIZ); setbuf(stdout, buf); puts("hello world"); //屏幕此时没有输出,因为存在buf数组里 system("pause"); fflush(stdout); //屏幕输出 system("pause"); return(0); }
setvbuf
int setvbuf ( FILE * stream, char * buffer, int mode, size_t size );
Change stream buffering- 设置缓冲方式(Full buffering,Line buffering,No buffering)
参数 描述 stream Pointer to a FILE object buffer User allocated buffer. Shall be at least size bytes long.如果空,会自动设置默认buffer(BUFSIZ) mode 三种 size Buffer size, in bytes. mode 描述 _IOFBF Full buffering,写出:buffer区间满,刷新,读入:buffer空,刷新 _IOLBF Line buffering,写出:buffer区满或碰到换行符,刷新,读入:buffer空,或换行符,刷新 _IONBF No buffering,没有缓冲区,buffer and size参数被忽略 返回 描述 成功 返回0 失败 非0 #pragma warning(disable:4996) #include<stdio.h> #include<stdlib.h> int main() { setvbuf(stdout, NULL, _IONBF, 512); puts("hello world"); //直接输出到屏幕,不需要刷新缓冲区 system("pause"); fflush(stdout); system("pause"); return(0); }
fflush
int fflush ( FILE * stream );
Flush stream- 刷新缓冲区
参考:
http://www.gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html#I_002fO-on-Streams -
C语言环行缓冲区 环形buffer
2019-07-25 20:38:35此文件是对于C语言编写环形缓冲区的编写,如何对于学习的指针使用,写一个自己的环形缓冲区,很哟意思,我得思路比较复杂,希望有好方法的多交流一下,我也学习一下 -
环形buffer C语言简单实现
2018-08-26 19:09:05#include <stdio.h> #include &...typedef struct circlebuffer { int size;//用于判断环形buffer是否是满的 int wroffset; int rdoffser; char * buf; int buflen; }circl... -
ring buffer的C语言实现
2019-04-12 16:51:32ring buffer实质上是在一块连续的内存上对数据进行写入和读取,只是在写入和读取的时候有些不同。每次读取的时候都要从开辟空间的地址加上一个读取的偏移量读取,相对应的,写入的时候也要从开辟空间的地址加上一个... -
C语言——循环buffer的实现
2013-05-18 14:25:27自己用C语言写的队列,实现循环buffer的功能。贴出来,跟大家一起讨论。 /* 参考: [源代码] C语言队列实现 http://avr.cnta.net/forum.php?mod=viewthread&tid=287 */ #if defined(__CIRCLE_BUFFER... -
protocol buffer生成C语言的实现
2019-07-26 16:37:39ubuntu中搭建Protocol Buffer环境 1、提示 Protocol Buffer原生没有对C的支持,只能使用protobuf-c这个第三方库 2、下载 Protocol Buffer和protobuf-c的安装包 参考图 下载链接 ... -
C语言实现ring buffer -- AWTK环形缓冲器及其应用
2021-01-17 20:41:31-- 来自百度百科 二、AWTK环形缓冲器的设计 AWTK使用C语言实现,采用面向对象的设计方法设计每一个子模块。它使用一个结构体封装对象的属性,通过对外提供接口的方式操作对象,环形缓冲器也是遵循这种方法设计的。 1...