4.2 KiB
4.2 KiB
liblist — 侵入式双向循环链表 API 参考
模块概述
liblist 是 Linux 内核风格的双向循环链表,纯头文件实现,C/C++ 兼容。
所有增删操作 O(1),遍历 O(n)。核心思想:将 struct list_head 嵌入宿主结构体,
通过 offsetof 从链表节点指针反推宿主指针。
数据结构
struct list_head
{
struct list_head *next; // 后继节点
struct list_head *prev; // 前驱节点
};
接口函数
初始化
LIST_HEAD(name)
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
编译期定义并初始化一个链表头。
示例:
LIST_HEAD(my_list); // 定义 my_list 并初始化为空链表
INIT_LIST_HEAD(h)
void INIT_LIST_HEAD(struct list_head *h);
运行时初始化一个已存在的链表头。
示例:
struct list_head head;
INIT_LIST_HEAD(&head);
添加
list_add(node, head)
头插法:将 node 插入到 head 之后(作为第一个元素)。
void list_add(struct list_head *node, struct list_head *head);
list_add_tail(node, head)
尾插法:将 node 插入到 head 之前(作为最后一个元素)。
void list_add_tail(struct list_head *node, struct list_head *head);
删除
list_del(entry)
从链表中移除节点(不释放内存)。
list_del_init(entry)
移除节点并重新初始化为自环,防止后续误操作导致悬空指针。
移动
list_move(list, head)
将节点移动到新链表头部。
list_move_tail(list, head)
将节点移动到新链表尾部。
替换
list_replace(old, node)
用 node 替换 old 的位置。
list_replace_init(old, node)
替换后初始化被替换节点。
判断
list_empty(head)
判断链表是否为空(头节点的 next 指向自身即为空)。
list_is_linked(entry)
判断节点是否已链入某个链表(非自环即为已链接)。
节点转宿主
list_entry(ptr, type, member)
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
从链表节点指针取回宿主结构体指针。
list_first_entry(head, type, member)
获取第一个宿主元素。
list_last_entry(head, type, member)
获取最后一个宿主元素。
list_first_entry_or_null(head, type, member)
安全获取第一个元素(链表空返回 NULL)。
遍历
list_for_each(pos, head)
遍历链表节点(仅获取 struct list_head * 指针)。
list_for_each_safe(pos, n, head)
安全遍历(可在遍历中删除当前节点 pos)。
list_for_each_entry(pos, head, member)
遍历宿主元素,最常用。
list_for_each_entry_safe(pos, n, head, member)
安全遍历宿主元素(可在遍历中删除 pos)。
拼接
list_splice_init(src, dst)
将 src 链表拼接到 dst 头部,src 被清空。
使用示例
#include "myBase.h"
#include "list.h"
// 定义宿主结构体
struct sensor
{
int id;
float value;
struct list_head node; // 嵌入的链表节点
};
int main(void)
{
// 定义链表头
LIST_HEAD(sensor_list);
// 创建 3 个传感器
struct sensor s1 = { .id = 1, .value = 25.5 };
struct sensor s2 = { .id = 2, .value = 30.0 };
struct sensor s3 = { .id = 3, .value = 22.1 };
// 尾插
list_add_tail(&s1.node, &sensor_list);
list_add_tail(&s2.node, &sensor_list);
list_add_tail(&s3.node, &sensor_list);
// 遍历并打印
struct sensor *pos;
list_for_each_entry(pos, &sensor_list, node)
{
printf("sensor %d: %.1f\n", pos->id, pos->value);
}
// 输出:
// sensor 1: 25.5
// sensor 2: 30.0
// sensor 3: 22.1
// 安全删除所有节点
struct sensor *tmp;
list_for_each_entry_safe(pos, tmp, &sensor_list, node)
{
printf("removing sensor %d\n", pos->id);
list_del(&pos->node);
free(pos); // 如果是动态分配的
}
printf("list empty: %d\n", list_empty(&sensor_list)); // 1
return 0;
}
依赖关系
- 依赖:
<stddef.h>(offsetof) - 被依赖: liblog, libdatacenter, 所有需要链表管理的模块