RingBuffer环形缓冲区C语言

简介

项目未能实现线程安全,仅供学习参考,工程项目请谨慎使用!!! RingBuffer 是一个基于C语言开发的环形缓冲区,适用于各嵌入式平台的串口收发等应用场景;在基本功能的基础上还提供了一个分段记录框架,方便数据管理;代码在AT32F403A平台上编译运行,经过简单的串口收发测试后暂未发现显性BUG

开始

https://github.com/netube99/RingBuffer/tree/main

基础功能 RingBuffer Base 的使用方法

//引用相关头文件
#include <stdint.h>
#include <stdio.h>
#include "ring_buffer.h"//创建一个数组作为数据存储空间
#define BUFFER_SIZE 128
static uint8_t buffer[BUFFER_SIZE];//创建环形缓冲区句柄
static ring_buffer rb;int main(void)
{//初始化环形缓冲区参数RB_Init(&rb, buffer, BUFFER_SIZE);//写入向环形缓冲区写入数据RB_Write_String(&rb, "hello world", 11);RB_Write_Byte(&rb, '!');RB_Write_Byte(&rb, 0x00);//删除环形缓冲区部分数据RB_Delete(&rb, 2);//获取已储存的数据长度uint32_t num = RB_Get_Length(&rb);//读出环形缓冲区中的数据并打印uint8_t get[16];RB_Read_String(&rb, get, num);printf("%s", get);//控制台输出内容//llo world!return 0;
}

分段框架 RingBuffer Chapter 的使用方法

//引用相关头文件
#include <stdint.h>
#include <stdio.h>
#include "ring_buffer_chapter.h"//创建两个数组,一个作为数据存储空间,一个用于记录分段信息
#define BASE_SIZE 128
static uint8_t buffer_base[BASE_SIZE];
#define CHAPTER_SIZE 16
static uint32_t buffer_chapter[CHAPTER_SIZE];//创建分段环形缓冲区句柄
static ring_buffer_chapter rbc;int main(void)
{//初始化分段环形缓冲区参数RBC_Init(&rbc, buffer_base, BASE_SIZE, buffer_chapter, CHAPTER_SIZE);//写入向环形缓冲区写入数据1,并记录分段结尾RBC_Write_String(&rbc, "string1", 7);RBC_Write_Byte(&rbc, '!');RBC_Write_Byte(&rbc, 0x00);RBC_Ending_Chapter(&rbc);//写入向环形缓冲区写入数据2,并记录分段结尾RBC_Write_String(&rbc, "string2", 7);RBC_Write_Byte(&rbc, '!');RBC_Write_Byte(&rbc, 0x00);RBC_Ending_Chapter(&rbc);//获取已储存的分段数量uint32_t num = RBC_Get_Chapter_Number(&rbc);//读出环形缓冲区中的数据并打印uint8_t get[16];for (uint32_t i = 0; i < num; i++){RBC_Read_Chapter(&rbc, get, NULL);printf("%s\r\n", get);}//控制台输出内容//string1!//string2!return 0;
}

ring_buffer.h

/*** \file ring_buffer.h* \brief 简易环形缓冲相关定义与声明* \author netube_99\netube@163.com* \date 2022.08.20* \version v0.4.0
*/
#ifndef _RING_BUFFER_H_
#define _RING_BUFFER_H_//返回值定义
#define RING_BUFFER_SUCCESS     0x01
#define RING_BUFFER_ERROR       0x00//环形缓冲区结构体
typedef struct
{uint32_t head ;             //操作头指针uint32_t tail ;             //操作尾指针uint32_t Length ;           //已储存的数据量uint8_t *array_addr ;       //缓冲区储存数组基地址uint32_t max_Length ;       //缓冲区最大可储存数据量
}ring_buffer;uint8_t RB_Init(ring_buffer *rb_handle, uint8_t *buffer_addr ,uint32_t buffer_size);               //初始化基础环形缓冲区
uint8_t RB_Delete(ring_buffer *rb_handle, uint32_t Length);                                        //从头指针开始删除指定长度的数据
uint8_t RB_Write_Byte(ring_buffer *rb_handle, uint8_t data);                                       //向缓冲区尾指针写一个字节
uint8_t RB_Write_String(ring_buffer *rb_handle, uint8_t *input_addr, uint32_t write_Length);       //向缓冲区尾指针写指定长度数据
uint8_t RB_Read_Byte(ring_buffer *rb_handle, uint8_t *output_addr);                                //从缓冲区头指针读一个字节
uint8_t RB_Read_String(ring_buffer *rb_handle, uint8_t *output_addr, uint32_t read_Length);        //从缓冲区头指针读指定长度数据
uint32_t RB_Get_Length(ring_buffer *rb_handle);                                                    //获取缓冲区里已储存的数据长度
uint32_t RB_Get_FreeSize(ring_buffer *rb_handle);                                                  //获取缓冲区可用储存空间#endif//#ifndef _RING_BUFFER_H_

ring_buffer.c

/*** \file ring_buffer.c* \brief 简易环形缓冲的实现* \author netube_99\netube@163.com* \date 2022.08.20* \version v0.4.0
*/#include <stdint.h>
#include <string.h>
#include "ring_buffer.h"/*** \brief 初始化新缓冲区* \param[out] rb_handle: 待初始化的缓冲区结构体句柄* \param[in] buffer_addr: 外部定义的缓冲区数组,类型必须为 uint8_t* \param[in] buffer_size: 外部定义的缓冲区数组空间* \return 返回缓冲区初始化的结果*      \arg RING_BUFFER_SUCCESS: 初始化成功*      \arg RING_BUFFER_ERROR: 初始化失败
*/
uint8_t RB_Init(ring_buffer *rb_handle, uint8_t *buffer_addr ,uint32_t buffer_size)
{//缓冲区数组空间必须大于2且小于数据类型最大值if(buffer_size < 2 || buffer_size == 0xFFFFFFFF)return RING_BUFFER_ERROR ; //初始化失败rb_handle->head = 0 ; //复位头指针rb_handle->tail = 0 ; //复位尾指针rb_handle->Length = 0 ; //复位已存储数据长度rb_handle->array_addr = buffer_addr ; //缓冲区储存数组基地址rb_handle->max_Length = buffer_size ; //缓冲区最大可储存数据量return RING_BUFFER_SUCCESS ; //缓冲区初始化成功
}/*** \brief 从头指针开始删除指定长度的数据* \param[out] rb_handle: 缓冲区结构体句柄* \param[in] Length: 要删除的长度* \return 返回删除指定长度数据结果*      \arg RING_BUFFER_SUCCESS: 删除成功*      \arg RING_BUFFER_ERROR: 删除失败
*/
uint8_t RB_Delete(ring_buffer *rb_handle, uint32_t Length)
{if(rb_handle->Length < Length)return RING_BUFFER_ERROR ;//已储存的数据量小于需删除的数据量else{if((rb_handle->head + Length) >= rb_handle->max_Length)rb_handle->head = Length - (rb_handle->max_Length - rb_handle->head);elserb_handle->head += Length ;    //头指针向前推进,抛弃数据rb_handle->Length -= Length ;      //重新记录有效数据长度return RING_BUFFER_SUCCESS ;//已储存的数据量小于需删除的数据量}
}/*** \brief 向缓冲区尾部写一个字节* \param[out] rb_handle: 缓冲区结构体句柄* \param[in] data: 要写入的字节* \return 返回缓冲区写字节的结果*      \arg RING_BUFFER_SUCCESS: 写入成功*      \arg RING_BUFFER_ERROR: 写入失败
*/
uint8_t RB_Write_Byte(ring_buffer *rb_handle, uint8_t data)
{//缓冲区数组已满,产生覆盖错误if(rb_handle->Length == (rb_handle->max_Length))return RING_BUFFER_ERROR ;else{*(rb_handle->array_addr + rb_handle->tail) = data;//基地址+偏移量,存放数据rb_handle->Length ++ ;//数据量计数+1rb_handle->tail ++ ;//尾指针后移}//如果尾指针超越了数组末尾,尾指针指向缓冲区数组开头,形成闭环if(rb_handle->tail > (rb_handle->max_Length - 1))rb_handle->tail = 0 ;return RING_BUFFER_SUCCESS ;
}/*** \brief 从缓冲区头指针读取一个字节* \param[out] rb_handle: 缓冲区结构体句柄* \param[out] output_addr: 读取的字节保存地址* \return 返回读取状态*      \arg RING_BUFFER_SUCCESS: 读取成功*      \arg RING_BUFFER_ERROR: 读取失败
*/
uint8_t RB_Read_Byte(ring_buffer *rb_handle, uint8_t *output_addr)
{if (rb_handle->Length != 0)//有数据未读出{*output_addr = *(rb_handle->array_addr + rb_handle->head);//读取数据rb_handle->head ++ ;rb_handle->Length -- ;//数据量计数-1//如果头指针超越了数组末尾,头指针指向数组开头,形成闭环if(rb_handle->head > (rb_handle->max_Length - 1))rb_handle->head = 0 ;return RING_BUFFER_SUCCESS ;}return RING_BUFFER_ERROR ;
}/*** \brief 向缓冲区尾部写指定长度的数据* \param[out] rb_handle: 缓冲区结构体句柄* \param[out] input_addr: 待写入数据的基地址* \param[in] write_Length: 要写入的字节数* \return 返回缓冲区尾部写指定长度字节的结果*      \arg RING_BUFFER_SUCCESS: 写入成功*      \arg RING_BUFFER_ERROR: 写入失败
*/
uint8_t RB_Write_String(ring_buffer *rb_handle, uint8_t *input_addr, uint32_t write_Length)
{//如果不够存储空间存放新数据,返回错误if((rb_handle->Length + write_Length) > (rb_handle->max_Length))return RING_BUFFER_ERROR ;else{//设置两次写入长度uint32_t write_size_a, write_size_b ;//如果顺序可用长度小于需写入的长度,需要将数据拆成两次分别写入if((rb_handle->max_Length - rb_handle->tail) < write_Length){write_size_a = rb_handle->max_Length - rb_handle->tail ;//从尾指针开始写到储存数组末尾write_size_b = write_Length - write_size_a ;//从储存数组开头写数据//分别拷贝a、b段数据到储存数组中memcpy(rb_handle->array_addr + rb_handle->tail, input_addr, write_size_a);memcpy(rb_handle->array_addr, input_addr + write_size_a, write_size_b);rb_handle->Length += write_Length ;//记录新存储了多少数据量rb_handle->tail = write_size_b ;//重新定位尾指针位置}else//如果顺序可用长度大于或等于需写入的长度,则只需要写入一次{write_size_a = write_Length ;//从尾指针开始写到储存数组末尾memcpy(rb_handle->array_addr + rb_handle->tail, input_addr, write_size_a);rb_handle->Length += write_Length ;//记录新存储了多少数据量rb_handle->tail += write_size_a ;//重新定位尾指针位置if(rb_handle->tail == rb_handle->max_Length)rb_handle->tail = 0 ;//如果写入数据后尾指针刚好写到数组尾部,则回到开头,防止越位}return RING_BUFFER_SUCCESS ;}
}/*** \brief 从缓冲区头部读指定长度的数据,保存到指定的地址* \param[out] rb_handle: 缓冲区结构体句柄* \param[out] output_addr: 读取的数据保存地址* \param[in] read_Length: 要读取的字节数* \return 返回缓冲区头部读指定长度字节的结果*      \arg RING_BUFFER_SUCCESS: 读取成功*      \arg RING_BUFFER_ERROR: 读取失败
*/
uint8_t RB_Read_String(ring_buffer *rb_handle, uint8_t *output_addr, uint32_t read_Length)
{if(read_Length > rb_handle->Length)return RING_BUFFER_ERROR ;else{uint32_t Read_size_a, Read_size_b ;if(read_Length > (rb_handle->max_Length - rb_handle->head)){Read_size_a = rb_handle->max_Length - rb_handle->head ;Read_size_b = read_Length - Read_size_a ;memcpy(output_addr, rb_handle->array_addr + rb_handle->head, Read_size_a);memcpy(output_addr + Read_size_a, rb_handle->array_addr, Read_size_b);rb_handle->Length -= read_Length ;//记录剩余数据量rb_handle->head = Read_size_b ;//重新定位头指针位置}else{Read_size_a = read_Length ;memcpy(output_addr, rb_handle->array_addr + rb_handle->head, Read_size_a);rb_handle->Length -= read_Length ;//记录剩余数据量rb_handle->head += Read_size_a ;//重新定位头指针位置if(rb_handle->head == rb_handle->max_Length)rb_handle->head = 0 ;//如果读取数据后头指针刚好写到数组尾部,则回到开头,防止越位}return RING_BUFFER_SUCCESS ;}
}/*** \brief 获取缓冲区里已储存的数据长度* \param[in] rb_handle: 缓冲区结构体句柄* \return 返回缓冲区里已储存的数据长度
*/
uint32_t RB_Get_Length(ring_buffer *rb_handle)
{return rb_handle->Length ;
}/*** \brief 获取缓冲区可用储存空间* \param[in] rb_handle: 缓冲区结构体句柄* \return 返回缓冲区可用储存空间
*/
uint32_t RB_Get_FreeSize(ring_buffer *rb_handle)
{return (rb_handle->max_Length - rb_handle->Length) ;
}

ring_buffer_chapter.h

/*** \file ring_buffer_chapter.h* \brief 简易分段环形缓冲相关定义与声明* \author netube_99\netube@163.com* \date 2022.09.25* \version v0.4.0
*/#ifndef _RING_BUFFER_CHAPTER_H_
#define _RING_BUFFER_CHAPTER_H_#include "ring_buffer.h"//返回值定义
#define RING_BUFFER_CHAPTER_SUCCESS     0x01
#define RING_BUFFER_CHAPTER_ERROR       0x00//环形缓冲分段结构体
typedef struct
{ring_buffer base_handle ;       //数据储存环形缓冲区句柄ring_buffer chapter_handle ;    //分段记录环形缓冲区句柄uint32_t head_chapter_length;   //当前头分段可读字节数uint32_t tail_chapter_length;   //当前尾分段暂存字节计数uint8_t init_flag;              //初始化完成标志位
}ring_buffer_chapter;uint8_t RBC_Init(ring_buffer_chapter *rbc_handle,\uint8_t *base_buffer_addr, uint32_t base_buffer_size,\uint32_t *chapter_buffer_addr, uint32_t chapter_buffer_size);                               //初始化带分段功能的环形缓冲区
uint8_t RBC_Write_Byte(ring_buffer_chapter *rbc_handle, uint8_t data);                                      //向尾分段里写一个字节
uint8_t RBC_Write_String(ring_buffer_chapter *rbc_handle, uint8_t *input_addr, uint32_t write_Length);      //向尾分段里写指定长度数据
uint8_t RBC_Ending_Chapter(ring_buffer_chapter *rbc_handle);                                                //分段结尾,完成一次分段记录
uint8_t RBC_Read_Byte(ring_buffer_chapter *rbc_handle, uint8_t *output_addr);                               //从头分段读取一个字节
uint8_t RBC_Read_Chapter(ring_buffer_chapter *rbc_handle, uint8_t *output_addr, uint32_t *output_Length);   //读取整个头分段
uint8_t RBC_Delete(ring_buffer_chapter *rbc_handle, uint32_t Chapter_Number);                               //从头分段开始删除指定数量的分段
uint32_t RBC_Get_head_Chapter_length(ring_buffer_chapter *rbc_handle);                                      //获取当前头分段的长度
uint32_t RBC_Get_Chapter_Number(ring_buffer_chapter *rbc_handle);                                           //获取当前已记录的分段数量
uint32_t RBC_Get_Base_Free_Size(ring_buffer_chapter *rbc_handle);                                           //获取数据环剩余可用空间
uint32_t RBC_Get_Chapter_Free_Size(ring_buffer_chapter *rbc_handle);                                        //获取剩余可记录的分段数量#endif

ring_buffer_chapter.c

/*** \file ring_buffer_chapter.c* \brief 简易分段环形缓冲的实现* \author netube_99\netube@163.com* \date 2022.09.25* \version v0.4.0
*/#include <stdint.h>
#include "ring_buffer_chapter.h"/*** \brief 初始化带分段功能的环形缓冲区* \param[out] rbc_handle: 待初始化的缓冲区结构体句柄* \param[in] base_buffer_addr: 数据环缓冲区数组基地址* \param[in] base_buffer_size: 数据环缓冲区数组空间大小* \param[in] chapter_buffer_addr: 分段环缓冲区数组基地址* \param[in] chapter_buffer_size: 分段环缓冲区数组空间大小* \return 返回缓冲区初始化的结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 初始化成功*      \arg RING_BUFFER_CHAPTER_ERROR: 初始化失败
*/
uint8_t RBC_Init(ring_buffer_chapter *rbc_handle,\uint8_t *base_buffer_addr, uint32_t base_buffer_size,\uint32_t *chapter_buffer_addr, uint32_t chapter_buffer_size)
{if(!RB_Init(&(rbc_handle->base_handle), base_buffer_addr, base_buffer_size))return RING_BUFFER_CHAPTER_ERROR ;if(!RB_Init(&(rbc_handle->chapter_handle), (uint8_t *)chapter_buffer_addr, chapter_buffer_size))return RING_BUFFER_CHAPTER_ERROR ;rbc_handle->head_chapter_length = 0 ;rbc_handle->tail_chapter_length = 0 ;rbc_handle->init_flag = 1 ;return RING_BUFFER_CHAPTER_SUCCESS ;
}/*** \brief 向当前尾分段写入一个字节* \param[out] rbc_handle: 分段版环形缓冲区结构体句柄* \param[in] data: 待写入的数据* \return 返回写入结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 写入成功*      \arg RING_BUFFER_CHAPTER_ERROR: 写入失败
*/
uint8_t RBC_Write_Byte(ring_buffer_chapter *rbc_handle, uint8_t data)
{if(!RBC_Get_Chapter_Free_Size(rbc_handle)) //检查分段环剩余空间是否允许新增一条分段记录return RING_BUFFER_CHAPTER_ERROR ;if(!RB_Write_Byte(&(rbc_handle->base_handle), data)) //向数据环尾指针写入一个字节return RING_BUFFER_CHAPTER_ERROR ;rbc_handle->tail_chapter_length ++ ; //尾分段暂存字节数加1return RING_BUFFER_CHAPTER_SUCCESS ;
}/*** \brief 向当前尾分段写入指定长度数据* \param[out] rbc_handle: 分段版环形缓冲区结构体句柄* \param[in] input_addr: 待写入数据的基地址* \param[in] write_Length: 要写入的字节数* \return 返回写入结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 写入成功*      \arg RING_BUFFER_CHAPTER_ERROR: 写入失败
*/
uint8_t RBC_Write_String(ring_buffer_chapter *rbc_handle, uint8_t *input_addr, uint32_t write_Length)
{if(!RBC_Get_Chapter_Free_Size(rbc_handle)) //检查分段环剩余空间是否允许新增一条分段记录return RING_BUFFER_CHAPTER_ERROR ;if(!RB_Write_String(&(rbc_handle->base_handle), input_addr, write_Length)) //向数据环尾指针写入指定长度数据return RING_BUFFER_CHAPTER_ERROR;               rbc_handle->tail_chapter_length += write_Length ; //累加新增的尾分段暂存字节数return RING_BUFFER_CHAPTER_SUCCESS ;
}/*** \brief 分段结尾,将暂存的字节计数保存为一条分段数据* \param[out] rbc_handle: 分段版环形缓冲区结构体句柄* \return 返回保存结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 保存成功*      \arg RING_BUFFER_CHAPTER_ERROR: 保存失败
*/
uint8_t RBC_Ending_Chapter(ring_buffer_chapter *rbc_handle)
{//如果尾分段有暂存但未结尾的数据if(rbc_handle->tail_chapter_length){//将当前尾分段暂存字节计数存入分段环中RB_Write_String(&(rbc_handle->chapter_handle), (uint8_t *)&rbc_handle->tail_chapter_length, 4);//如果当前储存的是分段环的首条分段记录,则当前头分段可读字节数等于当前尾分段暂存字节计数if(rbc_handle->init_flag){RB_Read_String(&(rbc_handle->chapter_handle), (uint8_t *)&rbc_handle->head_chapter_length, 4);rbc_handle->init_flag = 0 ;}rbc_handle->tail_chapter_length = 0 ;//当前尾分段暂存字节计数归零return RING_BUFFER_CHAPTER_SUCCESS ;}return RING_BUFFER_CHAPTER_ERROR ;
}/*** \brief 从头分段读取一个字节* \param[out] rbc_handle: 分段版环形缓冲区结构体句柄* \param[in] output_addr: 读取的字节保存地址* \return 返回读取结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 读取成功*      \arg RING_BUFFER_CHAPTER_ERROR: 读取失败
*/
uint8_t RBC_Read_Byte(ring_buffer_chapter *rbc_handle, uint8_t *output_addr)
{if(rbc_handle->head_chapter_length){RB_Read_Byte(&(rbc_handle->base_handle), output_addr);  //读取一个字节rbc_handle->head_chapter_length -- ;//如果当前头分段可读字节数为空if(!rbc_handle->head_chapter_length){//如果还有储存的分段记录,则读取到可读字节数变量中if(RBC_Get_Chapter_Number(rbc_handle))RB_Read_String(&(rbc_handle->chapter_handle), (uint8_t *)&rbc_handle->head_chapter_length, 4);//如果所有分段记录都已读取,重新置位初始化完成标志位(恢复到初始化后的状态)else rbc_handle->init_flag = 1 ;}return RING_BUFFER_CHAPTER_SUCCESS ;}return RING_BUFFER_CHAPTER_ERROR ;
}/*** \brief 读取完整的头分段数据* \param[out] rbc_handle: 分段版环形缓冲区结构体句柄* \param[in] output_addr: 读取的分段数据保存地址* \param[out] output_Length: 读取的分段数据长度保存地址,可为NULL* \return 返回读取结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 读取成功*      \arg RING_BUFFER_CHAPTER_ERROR: 读取失败
*/
uint8_t RBC_Read_Chapter(ring_buffer_chapter *rbc_handle, uint8_t *output_addr, uint32_t *output_Length)
{if(rbc_handle->head_chapter_length){RB_Read_String(&(rbc_handle->base_handle), output_addr, rbc_handle->head_chapter_length);  //读取整个头分段的数据if(output_Length != NULL)*output_Length = rbc_handle->head_chapter_length ;rbc_handle->head_chapter_length = 0 ;//如果还有储存的分段记录,则读取到可读字节数变量中if(RBC_Get_Chapter_Number(rbc_handle))RB_Read_String(&(rbc_handle->chapter_handle), (uint8_t *)&rbc_handle->head_chapter_length, 4);//如果所有分段记录都已读取,重新置位初始化完成标志位(恢复到初始化后的状态)else rbc_handle->init_flag = 1 ;return RING_BUFFER_CHAPTER_SUCCESS ;}return RING_BUFFER_CHAPTER_ERROR ;
}/*** \brief 从头分段开始删除指定数量的分段* \param[out] rbc_handle: 分段版环形缓冲区结构体句柄* \param[in] chapter_number: 需要删除的分段数量* \return 返回删除结果*      \arg RING_BUFFER_CHAPTER_SUCCESS: 删除成功*      \arg RING_BUFFER_CHAPTER_ERROR: 删除失败
*/
uint8_t RBC_Delete(ring_buffer_chapter *rbc_handle, uint32_t chapter_number)
{//检查已存分段数量是否满足参数if(RBC_Get_Chapter_Number(rbc_handle) >= chapter_number && chapter_number){uint32_t num = rbc_handle->head_chapter_length;//从分段环读取分段的长度进行累加for(uint32_t i=0; i<chapter_number - 1; i++){uint32_t buffer32 = 0 ;//从分段环中获取分段的长度进行累加,同时实现了分段环的空间释放RB_Read_String(&(rbc_handle->chapter_handle), (uint8_t *)&buffer32, 4);num += buffer32 ;}//从数据环删除指定长度的数据RB_Delete(&(rbc_handle->base_handle), num);rbc_handle->head_chapter_length = 0 ;//如果还有储存的分段记录,则读取到头分段可读字节数变量中if(RBC_Get_Chapter_Number(rbc_handle))RB_Read_String(&(rbc_handle->chapter_handle), (uint8_t *)&rbc_handle->head_chapter_length, 4);//如果所有分段记录都已读取,重新置位初始化完成标志位(恢复到初始化后的状态)elserbc_handle->init_flag = 1 ;return RING_BUFFER_CHAPTER_SUCCESS ;}else return RING_BUFFER_CHAPTER_ERROR ;
}/*** \brief 获取当前头分段的可读长度* \param[in] rbc_handle: 分段版环形缓冲区结构体句柄* \return 返回当前头分段的可读长度
*/
uint32_t RBC_Get_head_Chapter_length(ring_buffer_chapter *rbc_handle)
{return rbc_handle->head_chapter_length ;
}/*** \brief 获取当前储存的分段数量* \param[in] rbc_handle: 分段版环形缓冲区结构体句柄* \return 返回当前储存的分段数量
*/
uint32_t RBC_Get_Chapter_Number(ring_buffer_chapter *rbc_handle)
{uint32_t number = RB_Get_Length(&(rbc_handle->chapter_handle))/4 ;if(rbc_handle->head_chapter_length)if(!number) return 1 ;else return number + 1 ;return number ;
}/*** \brief 获取数据环剩余可用空间* \param[in] rbc_handle: 分段版环形缓冲区结构体句柄* \return 返回数据环剩余可用空间
*/
uint32_t RBC_Get_Base_Free_Size(ring_buffer_chapter *rbc_handle)
{return RB_Get_FreeSize(&(rbc_handle->base_handle)) ;
}/*** \brief 获取剩余可记录的分段数量* \param[in] rbc_handle: 分段版环形缓冲区结构体句柄* \return 返回剩余可记录的分段数量
*/
uint32_t RBC_Get_Chapter_Free_Size(ring_buffer_chapter *rbc_handle)
{return RB_Get_FreeSize(&(rbc_handle->chapter_handle))/4 ;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/744699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构与算法】:插入排序与希尔排序

&#x1f525;个人主页&#xff1a; Quitecoder &#x1f525;专栏: 数据结构与算法 欢迎大家来到初阶数据结构的最后一小节&#xff1a;排序 目录 1.排序的基本概念与分类1.1什么是排序的稳定性&#xff1f;1.2内排序与外排序内排序外排序 2.插入排序2.1实现插入排序2.3稳定性…

Linux:kubernetes(k8s)Deployment的操作(13)

创建deployment 命令 kubectl create deploy nginx-deploy --imagenginx:1.7.9 再去使用以下命令分别查询 ubectl get deploy kubectl get replicaset kubectl get pod 他是一个层层嵌套的一个关系 首先是创建了一个 deploy 里面包含着replicaset replicaset里面含有…

C++ lambda函数个人理解

及方便自己在函数内部定义函数 int main() {int i 1;auto c [](int a, int c) {return ab;};int d a(2, i);cout<<c;return 0; }格式&#xff1a; auto functionname [capture](parameters) -> return_type { /* … */ }; &#xff08;1&#xff09;[capture] &a…

WPF —— Grid网格布局

1 &#xff1a;Grid网格布局简介 Grid为WPF中最常用的布局容器, 作为View中的主要组成部分, 负责框架中整体的页面布局。 2&#xff1a;网格标签Grid.ColumnDef Grid.ColumnDefinitions自定义列 只能设置宽度 不能设置高度ColumnDefinition 每一个列可以设置宽度&#xff0c;…

有来团队后台项目-解析6

element-icon 引入 安装 在解析3中&#xff0c;已经安装过 创建plugins 文件夹 icons 文件 import type { App } from "vue"; import * as ElementPlusIconsVue from "element-plus/icons-vue";// 注册所有图标 export function setupElIcons(app: App…

使用docker搭建ELK进行日志收集

目录 docker安装es docker安装kibana 为es配置中文分词器 安装原生logstash 项目服务集成日志收集 为es设置登录密码 为kibana设置登录密码 为es容器设置内存限制 使用htop或者是docker进行内存使用查询 docker安装es 与自己的springBoot版本适配即可&#xff0c;下面…

鸿蒙开发实战:【电话服务子系统】

简介 电话服务子系统&#xff0c;提供了一系列的API用于获取无线蜂窝网络和SIM卡相关的一些信息。应用可以通过调用API来获取当前注册网络名称、网络服务状态、信号强度以及SIM卡的相关信息。 各个模块主要作用如下&#xff1a; 核心服务模块&#xff1a;主要功能是初始化RI…

Docker进阶:深入了解 Dockerfile

Docker进阶&#xff1a;深入了解 Dockerfile 一、Dockerfile 概述二、Dockerfile 优点三、Dockerfile 编写规则四、Dockerfile 中常用的指令1、FROM2、LABEL3、RUN4、CMD5、ENTRYPOINT6、COPY7、ADD8、WORKDIR9、 ENV10、EXPOSE11、VOLUME12、USER13、注释14、ONBUILD 命令15、…

U盘启动盘 制作Linux Ubuntu CentOS系统启动盘 系统安装

U盘启动盘 制作Linux Ubuntu CentOS系统启动盘 系统安装 准备条件 准备一个U盘&#xff0c;建议容量至少为8GB&#xff0c;以便存放系统镜像文件 一台已经安装好操作系统的计算机&#xff0c;用于制作U盘启动盘 Ubuntu和CentOS的Linux ISO镜像文件。可以从官方网站或相关资源…

【学一点RISC-V】RISC-V IMSIC

IMSIC RISC-V AIA 文档 第三章 Incoming MSI Controller (IMSIC) 传入 MSI 控制器&#xff08;IMSIC&#xff09;是一个可选的 RISC-V 硬件组件&#xff0c;与 hart 紧密相连&#xff0c;每个 hart 有一个 IMSIC。IMSIC 接收并记录 Hart 的传入消息信号中断 (MSI)&#xff0c;并…

mysql笔记:8. 视图

文章目录 创建视图修改视图删除视图通过视图更新数据1. 插入数据2. 更新数据3. 删除数据 查看视图信息1. DESCRIBE2. SHOW TABLE STATUS3. SHOW CREATE VIEW4. 在views表中查看 数据库中的视图是一个虚拟表。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。行…

【框架学习 | 第五篇】SpringMVC(常用注解、获取请求参数、域对象共享数据、拦截器、异常处理、上传/下载文件)

文章目录 1.SpringMVC简介1.1定义1.2主要组件1.3工作流程1.3.1简要流程1.3.2详细流程 1.4优缺点 2.常用注解3.获取请求参数3.1通过 HttpServletRequest 获取请求参数3.2通过控制器方法的形参获取请求参数3.2.1请求路径参数与方法形参一致3.2.2请求路径参数与方法形参不一致3.2.…

【附学习笔记】现在学网络安全主要是实战还是打CTF?

作为一个5年资深网络安全工程师前来分享我的看法。 在我看来&#xff0c;无论是实战还是打CTF&#xff08;Capture The Flag&#xff0c;夺旗赛&#xff09;&#xff0c;都是学习网络安全的重要方面&#xff0c;只是侧重点可能有所不同。 网络安全是一个复杂且不断发展的领域…

优橙内推四川专场——5G网络优化(中高级)工程师

可加入就业QQ群&#xff1a;374637347 联系老师内推简历投递邮箱&#xff1a;hrictyc.com 内推公司1&#xff1a;中邮建技术有限公司 内推公司2&#xff1a;重庆爱信思科技有限责任公司 内推公司3&#xff1a;重庆信科通信工程有限公司 中邮建技术有限公司 中邮建技术有限…

Go微服务: 基于Go Micro框架实现微服务调用

Go Micro 1 &#xff09;概述 在具体的项目开发过程中&#xff0c;开发者聚焦的是业务逻辑的开发和功能的实现大量的环境配置&#xff0c;调试搭建等基础性工作会耗费相当一部分的精力因此有必要将微服务架构中所涉及到的&#xff0c;相关的解决方案做集中管理和维护Go Micro …

ThreadX(RTOS)在Ubuntu编译,并执行案例

关于ThreadX编程的调试&#xff0c;本篇不包含如何正确使用该系统应用在实际项目中&#xff0c;旨在无设备下想要了解该系统。 系统环境&#xff1a;Ubuntu20、gcc、cmake、ninja 代码下载&#xff1a;ThreadX版本6.4.1 https://github.com/eclipse-threadx/threadx/tree/ma…

Redis的快速入门【全方位进攻】

目录 什么是Redis? Redis的应用场景 Redis的常用指令 Redis的持久化机制 缓存穿透、缓存击穿与缓存雪崩 1.缓存穿透 2.缓存击穿 3.缓存雪崩 后续会持续更新!!! 什么是Redis? Redis是一个开源的、使用ANSI C语言编写的高性能Key-Value数据库,支持网络通信,并且可以基于内…

springboot学习(八十六) springboot使用graalvm编译native程序

一、windows环境下 1.下载graalvm的jdk https://injdk.cn/ 下载windows版本 配置java环境变量&#xff0c;配置过程略 2.下载visual Studio Build Tools 下载地址&#xff1a;https://aka.ms/vs/17/release/vs_BuildTools.exe 安装后选择组件&#xff1a; 其中windows S…

Java创建数组、赋值的四种方式,声明+创建+初始化 详解

文章目录 一、创建数组的四种方式二、详解三、数组存储的弊端 一、创建数组的四种方式 以int数据类型为例 Test public void testNewArray() {//创建数组//法一int[] arr1 new int[]{1,2,3,4,5};System.out.println(arr1.length " " arr1[2]); //5 3//Arr…

Linux发展史

Linux发展史 ​ Linux是一款较为安全、快速、稳定的操作系统&#xff0c;常用于后端的服务器&#xff1b; 一、计算机的发展史 ​ 1946年世界上第一台计算机埃尼阿克出世&#xff0c;此时的计算机主要是用于军事领域的&#xff0c;如&#xff1a;计算导弹的弹道轨迹。这个时…