轻量级嵌入式数据结构库 - Zero-Malloc, Header-Only Friendly, C99
embedded-dslib 是一个专为资源受限嵌入式系统设计的 C 语言数据结构库。所有数据结构支持零 malloc 的静态分配模式,通过简单的宏配置即可切换到动态分配模式。适用于 STM32、ESP32、AVR 等各种嵌入式平台。
- 零 malloc 设计:所有数据结构使用预分配的静态缓冲区,无堆内存依赖
- 可选动态分配:通过
DS_USE_MALLOC=1切换到 malloc/free 模式 - 统一错误处理:所有 API 返回
ds_err_t错误码,不使用 assert - 位掩码优化:环形缓冲区利用 2^n 容量特性,用位与替代取模
- 完整中文注释:每个函数、参数、结构体都有详细中文说明
- 跨平台兼容:纯 C99 标准,无平台依赖,支持 ARM/RISC-V/x86
- 附带测试框架:内置轻量级测试框架,支持 PASS/FAIL + 耗时输出
| 数据结构 | 头文件 | 说明 | 典型应用 |
|---|---|---|---|
| 环形缓冲区 | ds_ringbuf.h |
2^n 大小,位掩码优化,批量读写 | UART DMA、音频缓冲 |
| 双向链表 | ds_linkedlist.h |
带哨兵头节点,支持反转 | 任务队列、消息链 |
| FIFO 队列 | ds_queue.h |
基于环形缓冲区 | 消息传递、中断缓冲 |
| 固定大小栈 | ds_stack.h |
基于数组,LIFO | 表达式求值、DFS |
| 哈希表 | ds_hashmap.h |
开放寻址,DJB2 哈希 | 命令解析、配置管理 |
| 优先级队列 | ds_priority_queue.h |
二叉小顶堆 | 任务调度、Dijkstra |
| 位域操作 | ds_bitfield.h |
uint32_t 数组位图 | 资源分配、标志管理 |
| 软件定时器 | ds_timer.h |
定时器池管理 | 周期任务、延时执行 |
| 事件总线 | ds_event.h |
发布/订阅模式 | 传感器通知、模块解耦 |
embedded-dslib/
├── inc/ # 头文件
│ ├── ds_common.h # 公共类型、错误码、配置宏
│ ├── ds_ringbuf.h # 环形缓冲区
│ ├── ds_linkedlist.h # 双向链表
│ ├── ds_queue.h # FIFO 队列
│ ├── ds_stack.h # 固定大小栈
│ ├── ds_hashmap.h # 哈希表
│ ├── ds_priority_queue.h # 优先级队列
│ ├── ds_bitfield.h # 位域操作
│ ├── ds_timer.h # 软件定时器
│ └── ds_event.h # 事件总线
├── src/ # 源文件实现
│ ├── ds_ringbuf.c
│ ├── ds_linkedlist.c
│ ├── ds_queue.c
│ ├── ds_stack.c
│ ├── ds_hashmap.c
│ ├── ds_priority_queue.c
│ ├── ds_bitfield.c
│ ├── ds_timer.c
│ └── ds_event.c
├── test/ # 单元测试
│ ├── test_framework.h # 测试框架
│ └── test_all.c # 完整测试(55+ 用例)
├── examples/ # 使用示例
│ ├── ringbuf_uart_example.c
│ ├── hashmap_cmd_example.c
│ ├── event_bus_example.c
│ └── timer_task_example.c
├── docs/
│ └── API_Reference.md # API 参考文档
├── CMakeLists.txt # CMake 构建脚本
├── .gitignore
└── README.md
#include "ds_ringbuf.h"
// 1. 定义缓冲区(大小必须为2的幂)
uint8_t rx_buffer[256];
// 2. 声明实例
ds_ringbuf_t rx_ring;
// 3. 初始化
ds_ringbuf_init(&rx_ring, rx_buffer, 256);
// 4. 使用
uint8_t ch;
ds_ringbuf_write(&rx_ring, 'A');
ds_ringbuf_read(&rx_ring, &ch); // ch == 'A'#include "ds_hashmap.h"
ds_hm_entry_t entries[32];
ds_hashmap_t cmd_map;
ds_hashmap_init(&cmd_map, entries, 32);
int led_on = 1;
ds_hashmap_put(&cmd_map, "led", &led_on);
int *val = ds_hashmap_get(&cmd_map, "led"); // val == &led_on#include "ds_event.h"
ds_event_sub_t subs[16];
ds_event_bus_t bus;
ds_event_bus_init(&bus, subs, 16);
ds_event_subscribe(&bus, EVT_TEMP, on_temp_update, NULL);
ds_event_publish(&bus, EVT_TEMP, &temperature);# 编译库 + 测试 + 示例
mkdir build && cd build
cmake ..
make
# 运行测试
./test_all
# 运行示例
./ringbuf_uart_example
./hashmap_cmd_example
./event_bus_example
./timer_task_example# 编译静态库
gcc -c src/*.c -I inc -Wall -O2
ar rcs libdslib.a *.o
# 编译测试
gcc test/test_all.c src/*.c -I inc -I test -o test_all
./test_all# 启用动态内存分配
cmake -DDSLIB_USE_MALLOC=ON ..
# 禁用参数校验(极致性能)
cmake -DDSLIB_DISABLE_CHECK=ON ..
# 仅编译库,不编译测试和示例
cmake -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF ..| 宏 | 默认值 | 说明 |
|---|---|---|
DS_USE_MALLOC |
0 | 设为 1 启用 malloc/free 分配 |
DS_ENABLE_CHECK |
1 | 设为 0 跳过参数校验 |
DS_MAX_INSTANCES |
4 | 静态池化最大实例数 |
测试平台:STM32F407 @ 168MHz, -O2 优化
| 操作 | 时间复杂度 | 典型耗时 |
|---|---|---|
| 环形缓冲区写入/读取 | O(1) | ~20ns |
| 环形缓冲区批量写入(64B) | O(n) | ~200ns |
| 链表头部插入 | O(1) | ~50ns |
| 链表尾部插入 | O(1) | ~50ns |
| 链表按索引访问 | O(n) | ~15ns * n |
| 队列入队/出队 | O(1) | ~30ns |
| 栈压入/弹出 | O(1) | ~20ns |
| 哈希表插入/查找 | O(1) 平均 | ~100ns |
| 优先级队列入堆/出堆 | O(log n) | ~80ns |
| 位域设置/测试 | O(1) | ~10ns |
- 将
inc/目录添加到 Include Paths - 将
src/目录下的.c文件添加到工程 - 在编译选项中添加
-D DS_USE_MALLOC=0(默认)
// 在 main.c 中
#include "ds_ringbuf.h"
#include "ds_timer.h"
// UART DMA接收
uint8_t uart_rx_buf[256];
ds_ringbuf_t uart_rx;
int main(void) {
HAL_Init();
// ...
ds_ringbuf_init(&uart_rx, uart_rx_buf, 256);
while (1) {
// 处理接收数据
uint8_t ch;
while (ds_ringbuf_read(&uart_rx, &ch) == DS_OK) {
// 处理字符
}
}
}# 将库作为组件放入 components/dslib/
# 在 CMakeLists.txt 中添加
set(DSLIB_SRCS components/dslib/src/*.c)
idf_component_register(SRCS ${DSLIB_SRCS}
INCLUDE_DIRS components/dslib/inc)MIT License
欢迎提交 Issue 和 Pull Request。请确保:
- 代码风格一致(snake_case,4 空格缩进)
- 新增数据结构包含完整的单元测试(至少 5 个用例)
- 更新 API 参考文档