github
https://github.com/HaHaHaHaHaGe/mynetstack
簡介
在說明環形數組之前,先來看一看通常大家使用內存的方式
這是一段內存空間,大小16字節,起始地址0x80000000,截止地址0x8000000F
在這段內存中若想爲其內存空間進行賦值操作,C語言下應當:
*(unsigned char*)(0x80000000) = 0x66;
很明顯這條指令將0x66 賦值到了 0x80000000這個內存空間中
同樣你也可以:
unsigned char i = 16
while(i--)
*(unsigned char*)(0x80000000 + i) = 0x66;
這樣你將把整個內存空間從 0x80000000 ~ 0x8000000F 全部賦值爲0x66,當然在現實應用中會賦值更有意義的數據,並非0x66
同樣你也可以讀取數組內的數據
unsigned char recv;
recv = *(unsigned char*)(0x80000000);
或者連續讀取內存中的數據
unsigned char recv[16];
unsigned char i = 16
while(i--)
recv = *(unsigned char*)(0x80000000 + i);
啊~一切是那麼的美好,我可以隨意的存儲、寫入我希望的數據
好,接下來咱們在做一些假設:首先寫入的人不再是你,而是其他人(程序)
那麼這樣一來問題就變得有些複雜了,
你並不能知道,對方什麼時間會向裏面寫入數據
所以我需要有一個標誌來代表是否有人向內存中寫入了數據
然後輪詢的檢測這個標誌,若此標誌被置位了,則代表裏面有新的數據,需要讀取數據了
好的,問題解決了
但是這只是理想情況下,但在現實應用中,很可能當標誌被置位時,我沒有能力一口氣全部讀取新數據,這時候又該怎麼辦呢?
我們可以在增加一個標誌,這個標誌表示我讀到的位置,而之前的寫標誌也更改爲寫到的位置,這樣一來,就會變成下面的樣子:
當寫入方寫入數據時只需要挪動寫標誌,讀取方只是要挪動讀標誌
而且,我也只需要檢測讀寫標誌的距離就可知道當前是否有新的數據了
一切看似近乎完美,但是卻有一個致命的問題:
當寫位置達到末尾時,這時候該怎麼辦呢?
如果置之不理,那麼很明顯下一次寫入的位置將是未知區域!,這是很危險的,一個野指針的存在比空指針更加的危險。
這時候就到環形數組發揮功效的時候了
環形數組,顧名思義,就像他的名字一樣,結構是個環形,當讀\寫指針超過0x8000000F時也不會造成嚴重事故,因爲他被重定向到了0x80000000
這便是環形數組了,當然內存自己本身不可能從硬件修改成環形結構,環形的結構是在軟件層面上定義的
函數說明
有關環形數組的文件在\mynetstack\Source\BasicDataStream\inc 與\mynetstack\Source\BasicDataStream\src 中
名稱爲 ringbuffer.c 與 ringbuffer.h
注:程序還在更新,以GITHUB爲準
/*
寫數據到緩衝區函數
入口參數:
ptr:操作對象
data:寫入的數據指針
datalen:寫入的數據長度
*/
void write_buffer_data(ringbuffer *ptr, u8* data, u32 datalen);
/*
釋放緩衝區函數
注:如果在創建時指定了已經開闢好的內存,
那麼該函數只會清理此模塊內部的變量,
不會更改外部的數據
入口參數:
ptr:操作對象
*/
u8 deinitial_buffer(ringbuffer *ptr);
/*
創建緩衝區函數
注:可在創建時指定已經開闢好的內存,
入口參數:
ptr:操作對象
self_mem: 是否由本函數自行分配空間,如果不需要,
應輸入NO並在操作對象的start ptr中分配好相應的空間
size: 需要開闢空間的大小
*/
u8 initial_buffer(ringbuffer *ptr, u8 self_mem, u32 size);
/*
外部寫入數據後使用此函數更新內部參數
入口參數:
ptr:操作對象
datalen:外部寫入的數據長度
*/
void write_buffer_len(ringbuffer *ptr, u32 datalen);
/*
獲取全部未讀數據
入口參數:
ptr:操作對象
len: 讀出數據的長度(字節)
preview:若爲YES則此次讀取不會修改ringbuff內指針狀態
*/
u8* get_unread_data(ringbuffer *ptr, u32 *len,u8 preview);
/*
獲取全部未讀數據的指針(分兩部分)
入口參數:
ptr:操作對象
ptr_1: 保存第一個指針
ptr_2: 保存第二個指針
len_1: 第一個指針內容的大小(字節)
len_2: 第二個指針內容的大小(字節)
preview:若爲YES則此次讀取不會修改ringbuff內指針狀態
*/
void get_unread_ptr(ringbuffer *ptr, u8** ptr_1, u8** ptr_2, u32* len_1, u32* len_2, u8 preview);
/*
手動更新read指針
注:一般在get_unread_ptr後根據自身情況使用
入口參數:
ptr:操作對象
*/
void update_readlocation(ringbuffer *ptr);