# liblist — 侵入式双向循环链表 API 参考 ## 模块概述 liblist 是 Linux 内核风格的双向循环链表,纯头文件实现,C/C++ 兼容。 所有增删操作 O(1),遍历 O(n)。核心思想:将 `struct list_head` 嵌入宿主结构体, 通过 `offsetof` 从链表节点指针反推宿主指针。 ## 数据结构 ```c struct list_head { struct list_head *next; // 后继节点 struct list_head *prev; // 前驱节点 }; ``` ## 接口函数 ### 初始化 #### LIST_HEAD(name) ```c #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) ``` 编译期定义并初始化一个链表头。 **示例**: ```c LIST_HEAD(my_list); // 定义 my_list 并初始化为空链表 ``` #### INIT_LIST_HEAD(h) ```c void INIT_LIST_HEAD(struct list_head *h); ``` 运行时初始化一个已存在的链表头。 **示例**: ```c struct list_head head; INIT_LIST_HEAD(&head); ``` ### 添加 #### list_add(node, head) 头插法:将 node 插入到 head 之后(作为第一个元素)。 ```c void list_add(struct list_head *node, struct list_head *head); ``` #### list_add_tail(node, head) 尾插法:将 node 插入到 head 之前(作为最后一个元素)。 ```c 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) ```c #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 被清空。 ## 使用示例 ```c #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; } ``` ## 依赖关系 - **依赖**: `` (offsetof) - **被依赖**: liblog, libdatacenter, 所有需要链表管理的模块