支持动态分配(malloc/free)和静态分配(用户提供缓冲区)两种模式,特别适合 MCU 等无动态内存环境。
博客地址:https://www.cnblogs.com/hellototoro/p/16838272.html
cd build
cmake ..
cmake --build . --config Release
./bin/Release/hlibc_examplecd build
cmake -DHLIBC_USE_STATIC_ALLOC=ON ..
cmake --build . --config Release
./bin/Release/hlibc_example- hlist - 双向链表,支持随机位置插入/删除
- hstack - 栈(LIFO),支持 push/pop/top
- hqueue - 队列(FIFO),支持 push/pop/front/rear
| 特性 | 动态分配 | 静态分配 |
|---|---|---|
| 创建 API | hlist_create(size) |
hlist_create_static(buf, buf_size, elem_size) |
| 内存来源 | malloc/free | 用户提供缓冲区 |
| 容量检查 | N/A | 支持 hlist_capacity() |
| 溢出保护 | N/A | 返回 HLIB_OVERFLOW |
| MCU 友好 | ❌ | ✅ |
- ✅ 无动态内存分配,完全可预测
- ✅ 栈分配缓冲区,零堆碎片
- ✅ 适合嵌入式/MCU 环境
- ✅ 编译时容量配置
双向序列容器,用于将它们的元素保持为线性排列,并允许在序列的任何位置插入和删除。
动态分配:
hlist_ptr_t hlist_create(uint32_t type_size);
void hlist_destroy(hlist_ptr_t list);
/* 示例 */
hlist_ptr_t list = hlist_create(sizeof(int));
hlist_destroy(list);静态分配:
hlist_ptr_t hlist_create_static(void* buffer, uint32_t buffer_size, uint32_t type_size);
void hlist_destroy_static(hlist_ptr_t list);
/* 示例 */
static uint8_t my_buffer[HLIST_CALC_BUFFER_SIZE(int, 16)]; /* 16个int */
hlist_ptr_t list = hlist_create_static(my_buffer, sizeof(my_buffer), sizeof(int));
hlist_destroy_static(list);uint32_t hlist_capacity(hlist_ptr_t list); /* 最大容量 */
uint32_t hlist_size(hlist_ptr_t list); /* 当前大小 */
int hlist_empty(hlist_ptr_t list); /* 是否为空 */hlist_iterator_ptr_t it = hlist_begin(list);
hlist_iter_forward(&it);
printf("it = %d\n", *(int*)hlist_iter_data(it));
/* 遍历 */
for (hlist_iterator_ptr_t it = hlist_begin(list); it != hlist_end(list); hlist_iter_forward(&it)) {
printf("%d ", *(int*)hlist_iter_data(it));
}/* 头部/尾部插入 */
hlib_status_t hlist_push_back(hlist_ptr_t list, const void* data, uint32_t data_size);
hlib_status_t hlist_push_front(hlist_ptr_t list, const void* data, uint32_t data_size);
/* 迭代器指定位置插入 */
hlib_status_t hlist_insert(hlist_ptr_t list, hlist_iterator_ptr_t it, const void* data, uint32_t data_size);
/* 示例 */
struct test_str {
char a;
int b;
};
/* 动态分配 */
hlist_ptr_t list = hlist_create(sizeof(struct test_str));
struct test_str t1 = {'a', 10};
hlist_push_back(list, &t1, sizeof(t1));
/* 静态分配 */
static uint8_t buf[HLIST_CALC_BUFFER_SIZE(struct test_str, 8)];
hlist_ptr_t list = hlist_create_static(buf, sizeof(buf), sizeof(struct test_str));
hlib_status_t status = hlist_push_back(list, &t1, sizeof(t1));
if (status == HLIB_OVERFLOW) {
printf("List is full!\n");
}void hlist_pop_back(hlist_ptr_t list);
void hlist_pop_front(hlist_ptr_t list);
void hlist_remove(hlist_ptr_t list, hlist_iterator_ptr_t it);Stack 容器遵循 LIFO(后进先出)语义。堆栈上最后推送的元素将第一个弹出。
动态分配:
hstack_ptr_t hstack_create(uint32_t type_size);
void hstack_destroy(hstack_ptr_t stack);静态分配:
hstack_ptr_t hstack_create_static(void* buffer, uint32_t buffer_size, uint32_t type_size);
void hstack_destroy_static(hstack_ptr_t stack);
/* 示例 */
static uint8_t buf[HSTACK_CALC_BUFFER_SIZE(int, 32)]; /* 32个int */
hstack_ptr_t stack = hstack_create_static(buf, sizeof(buf), sizeof(int));/* push/pop */
hlib_status_t hstack_push(hstack_ptr_t stack, const void* data, uint32_t data_size, void (*copy)(void*, const void*));
void hstack_pop(hstack_ptr_t stack);
/* 查询 */
void* hstack_top(hstack_ptr_t stack);
uint32_t hstack_size(hstack_ptr_t stack);
uint32_t hstack_capacity(hstack_ptr_t stack); /* 仅静态模式 */
int hstack_empty(hstack_ptr_t stack);Queue 容器遵循 FIFO(先进先出)语义。第一个推送的元素将第一个弹出。
动态分配:
hqueue_ptr_t hqueue_create(uint32_t type_size);
void hqueue_destroy(hqueue_ptr_t queue);静态分配:
hqueue_ptr_t hqueue_create_static(void* buffer, uint32_t buffer_size, uint32_t type_size);
void hqueue_destroy_static(hqueue_ptr_t queue);
/* 示例 */
static uint8_t buf[HQUEUE_CALC_BUFFER_SIZE(int, 8)]; /* 8个int */
hqueue_ptr_t queue = hqueue_create_static(buf, sizeof(buf), sizeof(int));/* push/pop */
hlib_status_t hqueue_push(hqueue_ptr_t queue, const void* data, uint32_t data_size, void (*copy)(void*, const void*));
void hqueue_pop(hqueue_ptr_t queue);
/* 查询 */
void* hqueue_front(hqueue_ptr_t queue);
void* hqueue_rear(hqueue_ptr_t queue);
uint32_t hqueue_size(hqueue_ptr_t queue);
uint32_t hqueue_capacity(hqueue_ptr_t queue); /* 仅静态模式 */
int hqueue_empty(hqueue_ptr_t queue);- ON: 启用静态分配模式(所有容器使用静态缓冲区)
- OFF: 启用动态分配模式(默认,使用 malloc/free)
- ON: 编译示例程序(默认)
- OFF: 仅编译库
1、为什么要写这个库?
在C语言中,由于不能泛型编程,所以能开箱即用的数据结构很少,一般都要自己造轮子。hlibc 提供了通用的容器实现,支持任意数据类型。
2、如何使用 C 语言进行"泛型"编程?
虽然在C语言中不能使用模板,但是可以使用万能指针(void*)来替代。
3、什么时候选择静态分配模式?
- 嵌入式/MCU 环境(无动态内存)
- 需要完全可预测的内存分配
- 实时系统对内存碎片敏感
- 容量固定且已知
4、如何计算缓冲区大小?
使用提供的宏:
HLIST_CALC_BUFFER_SIZE(type, capacity) /* list */
HSTACK_CALC_BUFFER_SIZE(type, capacity) /* stack */
HQUEUE_CALC_BUFFER_SIZE(type, capacity) /* queue */5、静态模式下容量溢出了怎么办?
insert/push 操作会返回 HLIB_OVERFLOW 状态码,可以检查返回值判断是否溢出:
hlib_status_t status = hlist_push_back(list, &data, sizeof(data));
if (status == HLIB_OVERFLOW) {
printf("List is full!\n");
}根据项目主页确定