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);
        else
            rb_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 ++ ;//数据量计数+1
        rb_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 ++ ; //尾分段暂存字节数加1
    return 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);
        //如果所有分段记录都已读取,重新置位初始化完成标志位(恢复到初始化后的状态)
        else
            rbc_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 ;
}
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ring Buffer环形缓冲区)是一种循环使用的缓冲区,常用于实现数据的异步传输。下面是一个简单的C语言实现环形缓冲区的代码示例。 ```c #include <stdio.h> #include <stdlib.h> #define BUFFER_SIZE 10 typedef struct { int *buffer; int head; int tail; int size; } RingBuffer; RingBuffer *create_ring_buffer(int size) { RingBuffer *rb = (RingBuffer *)malloc(sizeof(RingBuffer)); rb->buffer = (int *)calloc(size, sizeof(int)); rb->head = 0; rb->tail = 0; rb->size = size; return rb; } void destroy_ring_buffer(RingBuffer *rb) { free(rb->buffer); free(rb); } int is_empty(RingBuffer *rb) { return rb->head == rb->tail; } int is_full(RingBuffer *rb) { return (rb->tail + 1) % rb->size == rb->head; } void push(RingBuffer *rb, int value) { if (is_full(rb)) { printf("Ring buffer is full!\n"); return; } rb->buffer[rb->tail] = value; rb->tail = (rb->tail + 1) % rb->size; } int pop(RingBuffer *rb) { if (is_empty(rb)) { printf("Ring buffer is empty!\n"); return -1; } int value = rb->buffer[rb->head]; rb->head = (rb->head + 1) % rb->size; return value; } int main() { RingBuffer *rb = create_ring_buffer(BUFFER_SIZE); push(rb, 1); push(rb, 2); push(rb, 3); printf("Pop: %d\n", pop(rb)); printf("Pop: %d\n", pop(rb)); push(rb, 4); push(rb, 5); push(rb, 6); while (!is_empty(rb)) { printf("Pop: %d\n", pop(rb)); } destroy_ring_buffer(rb); return 0; } ``` 在这个示例中,我们定义了一个RingBuffer结构体,包含了一个整型数组作为缓冲区、头指针、尾指针和缓冲区大小。我们通过create_ring_buffer函数创建缓冲区,并通过destroy_ring_buffer函数销毁缓冲区。 我们还定义了is_empty和is_full函数用于判断缓冲区是否为空或已满,以及push和pop函数用于向缓冲区中添加或取出数据。 在main函数中,我们先向缓冲区中添加了三个整数,然后取出了前两个。接着,我们又向缓冲区中添加了三个整数,并通过while循环将缓冲区中的所有数据取出并打印。最后,我们销毁了缓冲区。 这个示例只是一个简单的实现,实际的环形缓冲区可能会更加复杂。但是,这个示例可以帮助你了解如何使用C语言实现环形缓冲区

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值