内核 List 操作

2025-03-25 266 0

Linux 内核中的 list.h 提供了一个 双向链表 实现,包含了一系列 宏和函数,用于高效操作链表。以下是常用的 list_head 相关函数和宏,并附带详细介绍。

🌟 链表结构

struct list_head {
    struct list_head *next, *prev;
};

next 指向下一个节点
prev 指向上一个节点
双向循环链表

🔹初始化链表

函数/宏 作用
INIT_LIST_HEAD(struct list_head *list) 初始化链表头,list 指向自身
LIST_HEAD(name) 定义并初始化链表头

✅ 示例

struct list_head my_list;
INIT_LIST_HEAD(&my_list); // 初始化

// 另一种方式
LIST_HEAD(my_list2);  // 直接定义一个初始化好的链表头

🔹添加节点

函数/宏 作用
list_add(struct list_head new, struct list_head head) 插入到头部(head 之后)
list_add_tail(struct list_head new, struct list_head head) 插入到尾部(head 之前)

✅ 示例

struct my_node {
    int data;
    struct list_head list;
};

struct my_node node;
INIT_LIST_HEAD(&node.list);

list_add(&node.list, &my_list); // 插入到头部
list_add_tail(&node.list, &my_list); // 插入到尾部

🔹删除节点

函数/宏 作用
list_del(struct list_head *entry) 删除 entry,并不会释放内存
list_del_init(struct list_head *entry) 删除 entry,并重新初始化它

✅ 示例

list_del(&node.list); // 删除 node
list_del_init(&node.list); // 删除并重新初始化,防止野指针

🔹判断链表是否为空

函数/宏 作用
list_empty(const struct list_head *head) 判断链表是否为空
list_empty_careful(const struct list_head *head) 多线程安全的空判断

✅ 示例

if (list_empty(&my_list)) {
    printf("链表为空\n");
}

🔹遍历链表

函数/宏 作用
list_for_each(pos, head) 遍历 list_head 结构
list_for_each_safe(pos, n, head) 安全遍历(可删除)
list_for_each_entry(pos, head, member) 直接获取结构体
list_for_each_entry_safe(pos, n, head, member) 安全遍历结构体(可删除)

✅ 示例:遍历 list_head

struct list_head *pos;
list_for_each(pos, &my_list) {
    struct my_node *node = list_entry(pos, struct my_node, list);
    printf("Data: %d\n", node->data);
}

✅ 示例:安全删除遍历

struct list_head *pos, *n;
list_for_each_safe(pos, n, &my_list) {
    struct my_node *node = list_entry(pos, struct my_node, list);
    list_del(pos);
    free(node);
}

✅ 示例:直接获取结构体

struct my_node *node;
list_for_each_entry(node, &my_list, list) {
    printf("Data: %d\n", node->data);
}

✅ 示例:安全删除遍历结构体

struct my_node *node, *tmp;
list_for_each_entry_safe(node, tmp, &my_list, list) {
    list_del(&node->list);
    free(node);
}

🔹获取链表中的元素

函数/宏 作用
list_entry(ptr, type, member) 通过 list_head 获取包含它的结构体
list_first_entry(head, type, member) 获取链表中的第一个元素
list_last_entry(head, type, member) 获取链表中的最后一个元素
list_next_entry(pos, member) 获取下一个元素
list_prev_entry(pos, member) 获取上一个元素

✅ 示例

struct my_node *first = list_first_entry(&my_list, struct my_node, list);
struct my_node *last = list_last_entry(&my_list, struct my_node, list);

🔹移动和替换

函数/宏 作用
list_move(new, head) 移动 new 到 head 头部
list_move_tail(new, head) 移动 new 到 head 尾部
list_replace(old, new) 用 new 替换 old
list_replace_init(old, new) 替换并初始化 old

✅ 示例

list_move(&node.list, &my_list); // 移动到头部
list_replace(&node.list, &node2.list); // 用 node2 替换 node

🔹计算链表偏移

函数/宏 作用
container_of(ptr, type, member) 通过成员指针获取结构体指针
offsetof(type, member) 获取成员偏移量

✅ 示例

struct my_node *node = container_of(ptr, struct my_node, list);
size_t offset = offsetof(struct my_node, list);

🔹双链表连接

函数/宏 作用
list_splice(list, head) 连接 list 到 head 头部
list_splice_tail(list, head) 连接 list 到 head 尾部
list_splice_init(list, head) 连接后清空 list
list_splice_tail_init(list, head) 连接 list 到 head 尾部后清空 list

✅ 示例

LIST_HEAD(new_list);
list_splice(&new_list, &my_list); // 连接两个链表

🌟 总结

类别 函数/宏 作用
初始化 INIT_LIST_HEAD()、LIST_HEAD() 初始化链表
添加节点 list_add()、list_add_tail() 添加到头部或尾部
删除节点 list_del()、list_del_init() 删除节点
遍历链表 list_for_each()、list_for_each_safe() 遍历 list_head
获取元素 list_entry()、list_first_entry() 获取结构体指针
移动/替换 list_move()、list_replace() 移动/替换节点
拼接链表 list_splice()、list_splice_tail() 连接链表

🔹 Linux 内核链表 list_head 是一个高效的双向循环链表。
🔹 内核链表操作主要通过 list_entry()list_for_each_entry() 遍历并操作数据。
🔹 list_for_each_safe() 用于 安全删除 避免 use-after-free 错误。

🚀 理解这些函数,能更高效地在 Linux 内核编程中操作链表!

相关文章

发布评论