🔧 Linux 内核链表结构概览
Linux 内核中的链表结构定义在头文件 <linux/list.h>
中。核心结构是:
cpp
struct list_head {
struct list_head *next, *prev;
};
它表示一个双向循环链表的节点。链表的所有操作都围绕这个结构体展开。
🧩 链表宏总览
以下是常用链表宏的功能简介:
宏名 | 作用简述 |
---|---|
LIST_HEAD(name) |
定义并初始化一个链表头 |
INIT_LIST_HEAD(ptr) |
初始化一个链表头指针 |
list_add(new, head) |
将 new 节点插入到 head 之后 |
list_add_tail(new, head) |
将 new 节点插入到 head 之前(尾部) |
list_del(entry) |
删除节点 |
list_replace(old, new) |
替换一个节点 |
list_empty(head) |
检查链表是否为空 |
list_entry(ptr, type, member) |
获取结构体指针 |
list_first_entry(ptr, type, member) |
获取第一个元素结构体指针 |
list_next_entry(pos, member) |
获取下一个元素结构体指针 |
list_for_each(pos, head) |
遍历链表(指针) |
list_for_each_entry(pos, head, member) |
遍历链表(结构体) |
list_for_each_safe(pos, n, head) |
安全遍历链表(可删除) |
list_for_each_entry_safe(pos, n, head, member) |
安全遍历结构体(可删除) |
list_for_each_prev(pos, head) |
反向遍历 |
list_for_each_entry_reverse(pos, head, member) |
反向结构体遍历 |
list_prepare_entry(pos, head) |
安全地返回前一个 entry |
✅ 1. LIST_HEAD(name)
📌 作用
定义并初始化一个链表头。
🧾 参数
name
:链表头的名字(变量名)
🧪 示例
cpp
// list_head_example1.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list); // 定义并初始化一个链表头
int main(void)
{
if (list_empty(&my_list))
printf("链表为空\n");
else
printf("链表非空\n");
return 0;
}
✅ 编译方式(需要支持内核头文件环境)
cpp
gcc -o list_head_example1 list_head_example1.c
📤 输出结果
cpp
链表为空
✅ 2. INIT_LIST_HEAD(ptr)
📌 作用
初始化一个已经定义好的链表头指针,确保其 next
和 prev
都指向自身,形成一个空的循环链表。
🧾 参数
ptr
:指向struct list_head
类型的指针变量,表示链表头。
💡 适用场景
当链表头不是通过 LIST_HEAD(name)
宏静态定义的,而是动态分配的或作为结构体成员时,需要使用此宏进行初始化。
🧪 示例
cpp
// init_list_head_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
int main(void)
{
struct list_head my_list
INIT_LIST_HEAD(&my_list) // 初始化链表头
if (list_empty(&my_list))
printf("链表为空\n")
else
printf("链表非空\n")
return 0
}
📤 输出结果
cpp
链表为空
✅ 3. list_add(new, head)
📌 作用
将新节点 new
插入到 head
节点之后,即作为链表的第一个元素插入(头插法)。
🧾 参数
-
new
:指向要插入的新节点的struct list_head
指针。 -
head
:指向链表头节点的struct list_head
指针。
💡 特点
新节点插入在 head
后面,head->next
指向新节点,适合实现栈结构(LIFO)。
🧪 示例
cpp
// list_add_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list) // 初始化链表头
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 111
node2->data = 222
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add(&node1->list, &my_list)
list_add(&node2->list, &my_list)
struct my_node *pos
list_for_each_entry(pos, &my_list, list)
{
printf("data: %d\n", pos->data)
}
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
data: 222
data: 111
✅ 4. list_add_tail(new, head)
📌 作用
将新节点 new
插入到 head
节点之前 ,即作为链表的最后一个元素插入(尾插法)。
🧾 参数
-
new
:指向要插入的新节点的struct list_head
指针。 -
head
:指向链表头节点的struct list_head
指针。
💡 特点
新节点成为链表的"尾部"节点,适合实现队列结构(FIFO)。
🧪 示例
cpp
// list_add_tail_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list) // 初始化链表头
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 111
node2->data = 222
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *pos
list_for_each_entry(pos, &my_list, list)
{
printf("data: %d\n", pos->data)
}
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
data: 111
data: 222
✅ 5. list_del(entry)
📌 作用
将链表中的某个节点 entry
从链表中删除,并不会释放内存,只断开指针。
🧾 参数
entry
:指向要删除的struct list_head
节点。
⚠️ 注意
-
被删除的节点仍然存在于内存中,需要手动
free()
; -
删除后,该节点的
next
和prev
不会自动清空(可选使用list_del_init()
初始化)。list_del(&node1->list)
删除了node1
节点,但是node1->list.prev
和node1->list.next
依然保留了原来的值。它们指向链表中曾经链接到node1
的节点。因此,删除后的节点仍然有next
和prev
指针,它们并没有被清空。list_del_init()
也用于从链表中删除节点,它不仅删除节点,还将被删除节点的next
和prev
指针设置为链表头节点的指针(即初始化节点)。这通常用于防止误用已经删除的节点。
🧪 示例
cpp
// list_del_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
struct my_node *node3 = malloc(sizeof(*node3))
node1->data = 111
node2->data = 222
node3->data = 333
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
INIT_LIST_HEAD(&node3->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
list_add_tail(&node3->list, &my_list)
// 删除 node2 节点
list_del(&node2->list)
struct my_node *pos
list_for_each_entry(pos, &my_list, list)
{
printf("data: %d\n", pos->data)
}
free(node1)
free(node2) // 注意:即使被删除,也要手动释放
free(node3)
return 0
}
📤 输出结果
cpp
data: 111
data: 333
✅ 6. list_replace(old, new)
📌 作用
将链表中的一个节点 old
替换为另一个节点 new
,原位置不变,链表结构保持完整。
🧾 参数
-
old
:要被替换掉的节点(struct list_head *
)。 -
new
:用于替换的新节点(struct list_head *
)。
💡 特点
-
替换后,
old
脱离链表,但链表中整体顺序保持; -
不初始化
old
,如需复用需手动INIT_LIST_HEAD()
。
🧪 示例
cpp
// list_replace_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
struct my_node *node3 = malloc(sizeof(*node3)) // 替换者
node1->data = 111
node2->data = 222
node3->data = 999 // 用这个替换 node2
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
INIT_LIST_HEAD(&node3->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
// 替换 node2 为 node3
list_replace(&node2->list, &node3->list)
struct my_node *pos
list_for_each_entry(pos, &my_list, list)
{
printf("data: %d\n", pos->data)
}
free(node1)
free(node2)
free(node3)
return 0
}
📤 输出结果
cpp
data: 111
data: 999
✅ 7. list_empty(head)
📌 作用
判断链表是否为空(即 head->next == head
且 head->prev == head
)。
🧾 参数
head
:指向链表头的struct list_head *
。
💡 返回值
-
空链表 → 返回
true
(非 0); -
非空链表 → 返回
false
(0);
🧪 示例
cpp
// list_empty_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
if (list_empty(&my_list))
printf("链表最初是空的\n")
struct my_node *node = malloc(sizeof(*node))
node->data = 100
INIT_LIST_HEAD(&node->list)
list_add(&node->list, &my_list)
if (!list_empty(&my_list))
printf("插入后链表非空\n")
list_del(&node->list)
if (list_empty(&my_list))
printf("删除后链表再次为空\n")
free(node)
return 0
}
📤 输出结果
cpp
链表最初是空的
插入后链表非空
删除后链表再次为空
✅ 8. list_entry(ptr, type, member)
📌 作用
通过链表节点指针 ptr
,获取它所在的结构体地址。
🧾 参数
-
ptr
:指向某个struct list_head
节点的指针; -
type
:包含该list_head
的结构体类型; -
member
:结构体中list_head
成员的名字。
💡 功能原理
通过偏移量(container_of
)从 list_head
成员地址回推结构体起始地址。
🧪 示例
cpp
// list_entry_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node = malloc(sizeof(*node))
node->data = 123
INIT_LIST_HEAD(&node->list)
list_add(&node->list, &my_list)
// 直接使用 list_entry 获取结构体指针
struct list_head *first = my_list.next
struct my_node *entry = list_entry(first, struct my_node, list)
printf("获取的结构体 data = %d\n", entry->data)
list_del(&node->list)
free(node)
return 0
}
📤 输出结果
cpp
获取的结构体 data = 123
✅ 9. list_first_entry(ptr, type, member)
📌 作用
获取链表 ptr
中的第一个元素(结构体指针),等价于:
cpp
list_entry((ptr)->next, type, member)
🧾 参数
-
ptr
:链表头指针(struct list_head *
); -
type
:结构体类型; -
member
:结构体中list_head
的成员名。
🧪 示例
cpp
// list_first_entry_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 10
node2->data = 20
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *first = list_first_entry(&my_list, struct my_node, list)
printf("第一个节点的数据是:%d\n", first->data)
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
第一个节点的数据是:10
✅ 10. list_last_entry(ptr, type, member)
📌 作用
获取链表 ptr
中的最后一个元素(结构体指针),等价于:
cpp
list_entry((ptr)->prev, type, member)
🧪 示例
cpp
// list_last_entry_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 10
node2->data = 20
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *last = list_last_entry(&my_list, struct my_node, list)
printf("最后一个节点的数据是:%d\n", last->data)
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
最后一个节点的数据是:20
✅ 11. list_for_each(pos, head)
📌 作用
遍历链表的每个 struct list_head
节点指针(不自动转换为结构体)。
🧾 参数
-
pos
:struct list_head *
,遍历用的临时变量; -
head
:链表头指针。
🧪 示例
cpp
// list_for_each_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 100
node2->data = 200
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct list_head *pos
list_for_each(pos, &my_list)
{
struct my_node *entry = list_entry(pos, struct my_node, list)
printf("遍历到节点数据: %d\n", entry->data)
}
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
遍历到节点数据: 100
遍历到节点数据: 200
✅ 12. list_for_each_prev(pos, head)
📌 作用
从链表尾部开始向前遍历链表。与 list_for_each
相对,后者从链表头开始向后遍历。
🧾 参数
-
pos
:struct list_head *
,用于遍历的临时变量; -
head
:链表头指针。
🧪 示例
cpp
// list_for_each_prev_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 100
node2->data = 200
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct list_head *pos
list_for_each_prev(pos, &my_list)
{
struct my_node *entry = list_entry(pos, struct my_node, list)
printf("倒序遍历到节点数据: %d\n", entry->data)
}
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
倒序遍历到节点数据: 200
倒序遍历到节点数据: 100
✅ 13. list_for_each_entry(pos, head, member)
📌 作用
通过 struct list_head
节点遍历整个链表,pos
是每次遍历时对应的结构体类型指针。
🧾 参数
-
pos
:结构体类型指针,遍历时指向每个链表元素; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧪 示例
cpp
// list_for_each_entry_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 10
node2->data = 20
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *pos
list_for_each_entry(pos, &my_list, list)
{
printf("遍历到节点数据: %d\n", pos->data)
}
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
遍历到节点数据: 10
遍历到节点数据: 20
✅ 14. list_for_each_entry_reverse(pos, head, member)
📌 作用
从链表尾部向前遍历,类似于 list_for_each_entry
,但是顺序是反的。
🧾 参数
-
pos
:结构体类型指针; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧪 示例
cpp
// list_for_each_entry_reverse_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 10
node2->data = 20
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *pos
list_for_each_entry_reverse(pos, &my_list, list)
{
printf("倒序遍历到节点数据: %d\n", pos->data)
}
free(node1)
free(node2)
return 0
}
📤 输出结果
cpp
倒序遍历到节点数据: 20
倒序遍历到节点数据: 10
✅ 15. list_for_each_safe(pos, n, head)
📌 作用
遍历链表的同时,安全地删除当前节点,防止因删除节点而导致链表破损。
🧾 参数
-
pos
:结构体类型指针,用于遍历每个节点; -
n
:临时指针,用于保存当前节点的下一个节点; -
head
:链表头指针。
🧪 示例
cpp
// list_for_each_safe_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 10
node2->data = 20
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *pos, *n
list_for_each_safe(pos, n, &my_list)
{
printf("遍历到节点数据: %d\n", pos->data)
list_del(&pos->list) // 删除当前节点
free(pos)
}
return 0
}
📤 输出结果
cpp
遍历到节点数据: 10
遍历到节点数据: 20
注意:此示例中,节点在遍历时被安全地删除。
✅ 16. list_for_each_entry_safe(pos, n, head, member)
📌 作用
安全地遍历链表并删除节点,避免删除过程中破坏链表结构。
🧾 参数
-
pos
:结构体类型指针; -
n
:临时指针; -
head
:链表头指针; -
member
:结构体中的list_head
成员名。
🧪 示例
cpp
// list_for_each_entry_safe_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
node1->data = 10
node2->data = 20
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
struct my_node *pos, *n
list_for_each_entry_safe(pos, n, &my_list, list)
{
printf("遍历到节点数据: %d\n", pos->data)
list_del(&pos->list)
free(pos)
}
return 0
}
📤 输出结果
cpp
遍历到节点数据: 10
遍历到节点数据: 20
✅ 17. list_for_each_entry_continue(pos, head, member)
📌 作用
继续从当前节点的下一个节点开始遍历。
🧾 参数
-
pos
:结构体类型指针; -
head
:链表头指针; -
member
:结构体中的list_head
成员名。
🧪 示例
cpp
// list_for_each_entry_continue_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
struct my_node *node3 = malloc(sizeof(*node3))
node1->data = 10
node2->data = 20
node3->data = 30
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
INIT_LIST_HEAD(&node3->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
list_add_tail(&node3->list, &my_list)
struct my_node *pos
list_for_each_entry(pos, &my_list, list)
{
if (pos->data == 10)
list_for_each_entry_continue(pos, &my_list, list)
else
printf("继续遍历到节点数据: %d\n", pos->data)
}
free(node1)
free(node2)
free(node3)
return 0
}
📤 输出结果
cpp
继续遍历到节点数据: 20
继续遍历到节点数据: 30
✅ 18. list_for_each_entry_from(pos, head, member)
📌 作用
从指定节点 pos
开始继续遍历链表。
🧾 参数
-
pos
:结构体类型指针; -
head
:链表头指针; -
member
:结构体中的 `list_head` 成员名
🧪 示例
cpp
// list_for_each_entry_from_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
struct my_node *node3 = malloc(sizeof(*node3))
node1->data = 10
node2->data = 20
node3->data = 30
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
INIT_LIST_HEAD(&node3->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
list_add_tail(&node3->list, &my_list)
struct my_node *pos
list_for_each_entry_from(pos, &my_list, list)
{
printf("从指定节点继续遍历到节点数据: %d\n", pos->data)
}
free(node1)
free(node2)
free(node3)
return 0
}
📤 输出结果
cpp
从指定节点继续遍历到节点数据: 10
从指定节点继续遍历到节点数据: 20
从指定节点继续遍历到节点数据: 30
✅ 19. list_for_each_entry_safe_reverse(pos, n, head, member)
📌 作用
安全地反向遍历链表,并删除节点。
🧾 参数
-
pos
:结构体类型指针; -
n
:临时指针; -
head
:链表头指针; -
member
:结构体中的list_head
成员名。
🧪 示例
cpp
// list_for_each_entry_safe_reverse_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
struct my_node *node3 = malloc(sizeof(*node3))
node1->data = 10
node2->data = 20
node3->data = 30
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
INIT_LIST_HEAD(&node3->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
list_add_tail(&node3->list, &my_list)
struct my_node *pos, *n
list_for_each_entry_safe_reverse(pos, n, &my_list, list)
{
printf("倒序遍历并删除节点数据: %d\n", pos->data)
list_del(&pos->list)
free(pos)
}
return 0
}
📤 输出结果
cpp
倒序遍历并删除节点数据: 30
倒序遍历并删除节点数据: 20
倒序遍历并删除节点数据: 10
✅ 20. list_prepare_entry(entry, head, member)
📌 作用
用于准备遍历时的入口,在遍历开始时通过 list_for_each_entry_continue
或其他方式继续遍历。
🧾 参数
-
entry
:结构体类型指针; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧠 一句话总结 list_prepare_entry()
它的作用就是:
⚠️保证你传给
list_for_each_entry_continue()
的不是 NULL。如果你传的是 NULL,它会自动用链表头
head
来替代,防止遍历出错。
🧃通俗比喻
想象一个队列(链表),你要从某人(比如"老王")后面继续往后找人打招呼。
-
如果你记得"老王"是谁(
ptr != NULL
),你可以从他后面开始打招呼。 -
如果你不记得谁是"老王"了(
ptr == NULL
),那你就从队伍头(head
)开始。
这个"准备老王或者队头"的动作,就是 list_prepare_entry()
做的事。
🧪 示例
cpp
// list_prepare_entry_example.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
struct my_node {
int data;
struct list_head list;
};
LIST_HEAD(my_list)
int main(void)
{
struct my_node *node1 = malloc(sizeof(*node1))
struct my_node *node2 = malloc(sizeof(*node2))
struct my_node *node3 = malloc(sizeof(*node3))
node1->data = 10
node2->data = 20
node3->data = 30
INIT_LIST_HEAD(&node1->list)
INIT_LIST_HEAD(&node2->list)
INIT_LIST_HEAD(&node3->list)
list_add_tail(&node1->list, &my_list)
list_add_tail(&node2->list, &my_list)
list_add_tail(&node3->list, &my_list)
struct my_node *pos = NULL, *entry
// 第一次遍历,查找数据为 10 的节点
list_for_each_entry(entry, &my_list, list)
{
if (entry->data == 10) {
pos = entry
break
}
}
// 从找到的节点后开始继续遍历
printf("从10之后继续遍历:\n")
list_for_each_entry_continue(list_prepare_entry(pos, &my_list, list), &my_list, list)
{
printf("遍历数据: %d\n", entry->data)
}
free(node1)
free(node2)
free(node3)
return 0
}
✅ 输出结果:
cpp
从10之后继续遍历:
遍历数据: 20
遍历数据: 30
✅ 21. list_entry_is_head(ptr, head, member)
📌 作用
判断某个节点是否是链表的头节点。
换句话说:
它判断当前节点是否是链表头节点,在很多遍历时可以用来确认是否回到了链表头。
🧾 参数
-
ptr
:链表节点指针; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧪 示例
场景:遍历一个自定义结构体链表,打印所有节点的数据,并避免头节点被误处理。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/list.h>
struct my_node {
int data
struct list_head list
}
int main()
{
struct my_node head
struct my_node node1, node2
INIT_LIST_HEAD(&head.list)
node1.data = 1
node2.data = 2
list_add(&node1.list, &head.list)
list_add(&node2.list, &head.list)
struct my_node *pos
list_for_each_entry(pos, &head.list, list)
{
printf("node: %d\n", pos->data)
if (list_entry_is_head(pos, &head.list, list))
{
printf("This node is head\n")
}
else
{
printf("This node is NOT head\n")
}
}
return 0
}
🔎 宏定义分析
cpp
#define list_entry_is_head(pos, head, member) \
(&pos->member == (head))
📤 输出结果
cpp
node: 2
This node is NOT head
node: 1
This node is NOT head
✅ 示例:演示 list_entry_is_head()
返回 true
cpp
#include <stdio.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/list.h>
struct my_node {
int data
struct list_head list
}
int main()
{
struct my_node head
// 初始化链表头
INIT_LIST_HEAD(&head.list)
// 使用 list_entry() 将 list_head 转换为 my_node*
struct my_node *entry = list_entry(&head.list, struct my_node, list)
// 使用 list_entry_is_head() 判断
if (list_entry_is_head(entry, &head.list, list))
{
printf("entry 是链表头节点\n")
}
else
{
printf("entry 不是链表头节点\n")
}
return 0
}