環形緩衝區C語言實現
阿新 • • 發佈:2019-01-12
1. 環形緩衝區的特性
1、先進新出
2、當緩衝區被使用完,且又有新的資料需要儲存時,丟掉歷史最久的資料,儲存最新資料
現實中的儲存介質都是線性的,因此我們需要做一下處理,才能在功能上實現環形緩衝區
演算法說明:
1、pHead和pTail分別是連續儲存介質的首地址和尾地址
2、pTail - pHead 的值是環形緩衝區的總長度
3、pValid 是使用區域的起始指標,取資料時的起點,當取資料時pValid要發生偏移
4、pValidTail 是使用區域的的結尾指標,存資料時的起點,當存資料時,pValidTail要發生偏移
5、現有長度為addLen位元組要存入,當pValidTail + addLen > pTail 時(超出了緩衝區,這時就要繞到開頭pHead)
int len1 = pTail - pValidTail;
int len2 = addLen - len1;
pValidTail = pHead + len2;//新的使用區的尾指標
6、判斷總長度是否變更,即是否有資料覆蓋pValid所指向的區域,如果有,要偏移pValid
下面是已驗證的程式碼
ringBuffer.h
#ifndef RINGBUFFER_H_ #define RINGBUFFER_H_ typedef unsigned char u8; typedef unsigned int u32; void initRingbuffer(void); int wirteRingbuffer(u8* buffer,u32 len); int readRingbuffer(u8* buffer,u32 len); u32 getRingbufferValidLen(void); void releaseRingbuffer(void); #endif /* RINGBUFFER_H_ */
ringBuffer.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include "ringBuffer.h" #define BUFFER_SIZE 16 //緩衝區的長度,可以修改 static u32 validLen;//已使用的資料長度 static u8* pHead = NULL;//環形儲存區的首地址 static u8* pTail = NULL;//環形儲存區的結尾地址 static u8* pValid = NULL;//已使用的緩衝區的首地址 static u8* pValidTail = NULL;//已使用的緩衝區的尾地址 /* * 初始化環形緩衝區 * 環形緩衝區這裡可以是malloc申請的記憶體,也可以是Flash儲存介質 * */ void initRingbuffer(void) { if(pHead == NULL) { pHead = (u8*) malloc(BUFFER_SIZE); } pValid = pValidTail = pHead; pTail = pHead + BUFFER_SIZE; validLen = 0; } /* * function:向緩衝區中寫入資料 * param:@buffer 寫入的資料指標 * @addLen 寫入的資料長度 * return:-1:寫入長度過大 * -2:緩衝區沒有初始化 * */ int wirteRingbuffer(u8* buffer,u32 addLen) { if(addLen > BUFFER_SIZE) return -2; if(pHead==NULL) return -1; assert(buffer); //將要存入的資料copy到pValidTail處 if(pValidTail + addLen > pTail)//需要分成兩段copy { int len1 = pTail - pValidTail; int len2 = addLen - len1; memcpy( pValidTail, buffer, len1); memcpy( pHead, buffer + len1, len2); pValidTail = pHead + len2;//新的有效資料區結尾指標 }else { memcpy( pValidTail, buffer, addLen); pValidTail += addLen;//新的有效資料區結尾指標 } //需重新計算已使用區的起始位置 if(validLen + addLen > BUFFER_SIZE) { int moveLen = validLen + addLen - BUFFER_SIZE;//有效指標將要移動的長度 if(pValid + moveLen > pTail)//需要分成兩段計算 { int len1 = pTail - pValid; int len2 = moveLen - len1; pValid = pHead + len2; }else { pValid = pValid + moveLen; } validLen = BUFFER_SIZE; }else { validLen += addLen; } return 0; } /* * function:從緩衝區內取出資料 * param :@buffer:接受讀取資料的buffer * @len:將要讀取的資料的長度 * return :-1:沒有初始化 * >0:實際讀取的長度 * */ int readRingbuffer(u8* buffer,u32 len) { if(pHead==NULL) return -1; assert(buffer); if(validLen ==0) return 0; if( len > validLen) len = validLen; if(pValid + len > pTail)//需要分成兩段copy { int len1 = pTail - pValid; int len2 = len - len1; memcpy( buffer, pValid, len1);//第一段 memcpy( buffer+len1, pHead, len2);//第二段,繞到整個儲存區的開頭 pValid = pHead + len2;//更新已使用緩衝區的起始 }else { memcpy( buffer, pValid, len); pValid = pValid +len;//更新已使用緩衝區的起始 } validLen -= len;//更新已使用緩衝區的長度 return len; } /* * function:獲取已使用緩衝區的長度 * return :已使用的buffer長度 * */ u32 getRingbufferValidLen(void) { return validLen; } /* * function:釋放環形緩衝區 * */ void releaseRingbuffer(void) { if(pHead!=NULL) free(pHead); pHead = NULL; }
---------------------
作者:最好的濤
來源:CSDN
原文:https://blog.csdn.net/maowentao0416/article/details/81984269
版權宣告:本文為博主原創文章,轉載請附上博文連結!