You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C语言的多数据类型循环缓冲区实现需求(适配外部RAM)

多类型无malloc依赖的C循环缓冲区实现方案

针对嵌入式外部RAM场景(无法使用malloc),同时支持char、short、int等所有有符号/无符号整数类型的循环缓冲区,可通过泛型控制块+宏封装的方式实现,既避免重复代码,又完全脱离堆内存依赖。

核心实现代码

1. 通用控制块结构体

这个结构体只管理缓冲区的读写状态,不存储缓冲区指针,避免类型绑定:

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef struct {
    size_t head;     // 写入位置(以元素为单位)
    size_t tail;     // 读取位置(以元素为单位)
    size_t max_len;  // 缓冲区可容纳的最大元素数量
    bool full;       // 缓冲区满标记
} circular_buf_ctrl_t;

2. 类型安全的操作宏

通过宏封装所有缓冲区操作,自动适配不同数据类型,同时保证类型安全:

// 初始化:需提前分配好缓冲区和控制块,传入类型和元素数量
#define CIRCULAR_BUF_INIT(ctrl_ptr, buf_ptr, elem_type, elem_count) \
    do { \
        (ctrl_ptr)->head = 0; \
        (ctrl_ptr)->tail = 0; \
        (ctrl_ptr)->max_len = (elem_count); \
        (ctrl_ptr)->full = false; \
        (void)(buf_ptr); /* 仅用于编译期类型检查,确保buf_ptr是elem_type* */ \
    } while(0)

// 判断缓冲区是否为空
#define CIRCULAR_BUF_IS_EMPTY(ctrl_ptr) \
    (!((ctrl_ptr)->full) && ((ctrl_ptr)->head == (ctrl_ptr)->tail))

// 判断缓冲区是否已满
#define CIRCULAR_BUF_IS_FULL(ctrl_ptr) \
    ((ctrl_ptr)->full)

// 重置缓冲区
#define CIRCULAR_BUF_RESET(ctrl_ptr) \
    do { \
        (ctrl_ptr)->head = 0; \
        (ctrl_ptr)->tail = 0; \
        (ctrl_ptr)->full = false; \
    } while(0)

// 尝试写入单个元素:成功返回0,失败返回-1
#define CIRCULAR_BUF_TRY_PUT(ctrl_ptr, buf_ptr, elem_type, data) \
    ({ \
        int ret = -1; \
        if (!CIRCULAR_BUF_IS_FULL(ctrl_ptr)) { \
            ((elem_type*)(buf_ptr))[(ctrl_ptr)->head] = (data); \
            (ctrl_ptr)->head++; \
            if ((ctrl_ptr)->head >= (ctrl_ptr)->max_len) { \
                (ctrl_ptr)->head = 0; \
            } \
            (ctrl_ptr)->full = ((ctrl_ptr)->head == (ctrl_ptr)->tail); \
            ret = 0; \
        } \
        ret; \
    })

// 尝试读取单个元素:成功返回0,数据存入data_ptr,失败返回-1
#define CIRCULAR_BUF_TRY_GET(ctrl_ptr, buf_ptr, elem_type, data_ptr) \
    ({ \
        int ret = -1; \
        if (!CIRCULAR_BUF_IS_EMPTY(ctrl_ptr)) { \
            *(data_ptr) = ((elem_type*)(buf_ptr))[(ctrl_ptr)->tail]; \
            (ctrl_ptr)->tail++; \
            if ((ctrl_ptr)->tail >= (ctrl_ptr)->max_len) { \
                (ctrl_ptr)->tail = 0; \
            } \
            (ctrl_ptr)->full = false; \
            ret = 0; \
        } \
        ret; \
    })

使用示例

在外部RAM中提前分配缓冲区和控制块(通过编译器属性指定段,具体语法根据你的工具链调整),然后直接调用宏操作:

// 假设外部RAM段用EXTERN_RAM标记
#define EXTERN_RAM __attribute__((section(".extern_ram")))

// 8位无符号缓冲区:100个元素
EXTERN_RAM uint8_t u8_buf[100];
EXTERN_RAM circular_buf_ctrl_t u8_ctrl;

// 16位有符号缓冲区:50个元素
EXTERN_RAM int16_t s16_buf[50];
EXTERN_RAM circular_buf_ctrl_t s16_ctrl;

// 32位无符号缓冲区:20个元素
EXTERN_RAM uint32_t u32_buf[20];
EXTERN_RAM circular_buf_ctrl_t u32_ctrl;

void demo(void) {
    // 初始化各缓冲区
    CIRCULAR_BUF_INIT(&u8_ctrl, u8_buf, uint8_t, 100);
    CIRCULAR_BUF_INIT(&s16_ctrl, s16_buf, int16_t, 50);
    CIRCULAR_BUF_INIT(&u32_ctrl, u32_buf, uint32_t, 20);

    // 写入数据
    CIRCULAR_BUF_TRY_PUT(&u8_ctrl, u8_buf, uint8_t, 0xAB);
    CIRCULAR_BUF_TRY_PUT(&s16_ctrl, s16_buf, int16_t, -1234);
    CIRCULAR_BUF_TRY_PUT(&u32_ctrl, u32_buf, uint32_t, 0x12345678);

    // 读取数据
    uint8_t read_u8;
    if (CIRCULAR_BUF_TRY_GET(&u8_ctrl, u8_buf, uint8_t, &read_u8) == 0) {
        // 处理读取到的u8数据
    }

    int16_t read_s16;
    if (CIRCULAR_BUF_TRY_GET(&s16_ctrl, s16_buf, int16_t, &read_s16) == 0) {
        // 处理读取到的s16数据
    }
}

方案优势

  1. 无malloc依赖:所有内存由用户提前静态分配,完全避开嵌入式场景下堆内存不足或malloc不可用的问题
  2. 类型安全:编译期通过宏的类型检查避免类型混用错误
  3. 零代码冗余:一套宏支持所有整数类型,无需为每个类型重复编写结构体和函数
  4. 逻辑兼容经典实现:核心的head/tail/full状态管理逻辑和经典循环缓冲区实现一致,易于理解和维护

内容的提问来源于stack exchange,提问作者V.Ajall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:45:34