RTU_ALL_AI/docs/public/liblist/API-liblist.md

4.2 KiB
Raw Blame History

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, 所有需要链表管理的模块