Linux 内核链表宏的详细解释
🔧 Linux 内核链表结构概览
Linux 内核中的链表结构定义在头文件 <linux/list.h>
中。核心结构是:
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
:链表头的名字(变量名)
🧪 示例
// 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");elseprintf("链表非空\n");return 0;
}
✅ 编译方式(需要支持内核头文件环境)
gcc -o list_head_example1 list_head_example1.c
📤 输出结果
链表为空
✅ 2. INIT_LIST_HEAD(ptr)
📌 作用
初始化一个已经定义好的链表头指针,确保其 next
和 prev
都指向自身,形成一个空的循环链表。
🧾 参数
-
ptr
:指向struct list_head
类型的指针变量,表示链表头。
💡 适用场景
当链表头不是通过 LIST_HEAD(name)
宏静态定义的,而是动态分配的或作为结构体成员时,需要使用此宏进行初始化。
🧪 示例
// 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_listINIT_LIST_HEAD(&my_list) // 初始化链表头if (list_empty(&my_list))printf("链表为空\n")elseprintf("链表非空\n")return 0
}
📤 输出结果
链表为空
✅ 3. list_add(new, head)
📌 作用
将新节点 new
插入到 head
节点之后,即作为链表的第一个元素插入(头插法)。
🧾 参数
-
new
:指向要插入的新节点的struct list_head
指针。 -
head
:指向链表头节点的struct list_head
指针。
💡 特点
新节点插入在 head
后面,head->next
指向新节点,适合实现栈结构(LIFO)。
🧪 示例
// 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 = 111node2->data = 222INIT_LIST_HEAD(&node1->list)INIT_LIST_HEAD(&node2->list)list_add(&node1->list, &my_list)list_add(&node2->list, &my_list)struct my_node *poslist_for_each_entry(pos, &my_list, list){printf("data: %d\n", pos->data)}free(node1)free(node2)return 0
}
📤 输出结果
data: 222
data: 111
✅ 4. list_add_tail(new, head)
📌 作用
将新节点 new
插入到 head
节点之前,即作为链表的最后一个元素插入(尾插法)。
🧾 参数
-
new
:指向要插入的新节点的struct list_head
指针。 -
head
:指向链表头节点的struct list_head
指针。
💡 特点
新节点成为链表的“尾部”节点,适合实现队列结构(FIFO)。
🧪 示例
// 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 = 111node2->data = 222INIT_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 *poslist_for_each_entry(pos, &my_list, list){printf("data: %d\n", pos->data)}free(node1)free(node2)return 0
}
📤 输出结果
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
指针设置为链表头节点的指针(即初始化节点)。这通常用于防止误用已经删除的节点。
🧪 示例
// 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 = 111node2->data = 222node3->data = 333INIT_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 *poslist_for_each_entry(pos, &my_list, list){printf("data: %d\n", pos->data)}free(node1)free(node2) // 注意:即使被删除,也要手动释放free(node3)return 0
}
📤 输出结果
data: 111
data: 333
✅ 6. list_replace(old, new)
📌 作用
将链表中的一个节点 old
替换为另一个节点 new
,原位置不变,链表结构保持完整。
🧾 参数
-
old
:要被替换掉的节点(struct list_head *
)。 -
new
:用于替换的新节点(struct list_head *
)。
💡 特点
-
替换后,
old
脱离链表,但链表中整体顺序保持; -
不初始化
old
,如需复用需手动INIT_LIST_HEAD()
。
🧪 示例
// 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 = 111node2->data = 222node3->data = 999 // 用这个替换 node2INIT_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 为 node3list_replace(&node2->list, &node3->list)struct my_node *poslist_for_each_entry(pos, &my_list, list){printf("data: %d\n", pos->data)}free(node1)free(node2)free(node3)return 0
}
📤 输出结果
data: 111
data: 999
✅ 7. list_empty(head)
📌 作用
判断链表是否为空(即 head->next == head
且 head->prev == head
)。
🧾 参数
-
head
:指向链表头的struct list_head *
。
💡 返回值
-
空链表 → 返回
true
(非 0); -
非空链表 → 返回
false
(0);
🧪 示例
// 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 = 100INIT_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
}
📤 输出结果
链表最初是空的
插入后链表非空
删除后链表再次为空
✅ 8. list_entry(ptr, type, member)
📌 作用
通过链表节点指针 ptr
,获取它所在的结构体地址。
🧾 参数
-
ptr
:指向某个struct list_head
节点的指针; -
type
:包含该list_head
的结构体类型; -
member
:结构体中list_head
成员的名字。
💡 功能原理
通过偏移量(container_of
)从 list_head
成员地址回推结构体起始地址。
🧪 示例
// 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 = 123INIT_LIST_HEAD(&node->list)list_add(&node->list, &my_list)// 直接使用 list_entry 获取结构体指针struct list_head *first = my_list.nextstruct my_node *entry = list_entry(first, struct my_node, list)printf("获取的结构体 data = %d\n", entry->data)list_del(&node->list)free(node)return 0
}
📤 输出结果
获取的结构体 data = 123
✅ 9. list_first_entry(ptr, type, member)
📌 作用
获取链表 ptr
中的第一个元素(结构体指针),等价于:
list_entry((ptr)->next, type, member)
🧾 参数
-
ptr
:链表头指针(struct list_head *
); -
type
:结构体类型; -
member
:结构体中list_head
的成员名。
🧪 示例
// 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 = 10node2->data = 20INIT_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
}
📤 输出结果
第一个节点的数据是:10
✅ 10. list_last_entry(ptr, type, member)
📌 作用
获取链表 ptr
中的最后一个元素(结构体指针),等价于:
list_entry((ptr)->prev, type, member)
🧪 示例
// 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 = 10node2->data = 20INIT_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
}
📤 输出结果
最后一个节点的数据是:20
✅ 11. list_for_each(pos, head)
📌 作用
遍历链表的每个 struct list_head
节点指针(不自动转换为结构体)。
🧾 参数
-
pos
:struct list_head *
,遍历用的临时变量; -
head
:链表头指针。
🧪 示例
// 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 = 100node2->data = 200INIT_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 *poslist_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
}
📤 输出结果
遍历到节点数据: 100
遍历到节点数据: 200
✅ 12. list_for_each_prev(pos, head)
📌 作用
从链表尾部开始向前遍历链表。与 list_for_each
相对,后者从链表头开始向后遍历。
🧾 参数
-
pos
:struct list_head *
,用于遍历的临时变量; -
head
:链表头指针。
🧪 示例
// 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 = 100node2->data = 200INIT_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 *poslist_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
}
📤 输出结果
倒序遍历到节点数据: 200
倒序遍历到节点数据: 100
✅ 13. list_for_each_entry(pos, head, member)
📌 作用
通过 struct list_head
节点遍历整个链表,pos
是每次遍历时对应的结构体类型指针。
🧾 参数
-
pos
:结构体类型指针,遍历时指向每个链表元素; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧪 示例
// 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 = 10node2->data = 20INIT_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 *poslist_for_each_entry(pos, &my_list, list){printf("遍历到节点数据: %d\n", pos->data)}free(node1)free(node2)return 0
}
📤 输出结果
遍历到节点数据: 10
遍历到节点数据: 20
✅ 14. list_for_each_entry_reverse(pos, head, member)
📌 作用
从链表尾部向前遍历,类似于 list_for_each_entry
,但是顺序是反的。
🧾 参数
-
pos
:结构体类型指针; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧪 示例
// 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 = 10node2->data = 20INIT_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 *poslist_for_each_entry_reverse(pos, &my_list, list){printf("倒序遍历到节点数据: %d\n", pos->data)}free(node1)free(node2)return 0
}
📤 输出结果
倒序遍历到节点数据: 20
倒序遍历到节点数据: 10
✅ 15. list_for_each_safe(pos, n, head)
📌 作用
遍历链表的同时,安全地删除当前节点,防止因删除节点而导致链表破损。
🧾 参数
-
pos
:结构体类型指针,用于遍历每个节点; -
n
:临时指针,用于保存当前节点的下一个节点; -
head
:链表头指针。
🧪 示例
// 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 = 10node2->data = 20INIT_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, *nlist_for_each_safe(pos, n, &my_list){printf("遍历到节点数据: %d\n", pos->data)list_del(&pos->list) // 删除当前节点free(pos)}return 0
}
📤 输出结果
遍历到节点数据: 10
遍历到节点数据: 20
注意:此示例中,节点在遍历时被安全地删除。
✅ 16. list_for_each_entry_safe(pos, n, head, member)
📌 作用
安全地遍历链表并删除节点,避免删除过程中破坏链表结构。
🧾 参数
-
pos
:结构体类型指针; -
n
:临时指针; -
head
:链表头指针; -
member
:结构体中的list_head
成员名。
🧪 示例
// 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 = 10node2->data = 20INIT_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, *nlist_for_each_entry_safe(pos, n, &my_list, list){printf("遍历到节点数据: %d\n", pos->data)list_del(&pos->list)free(pos)}return 0
}
📤 输出结果
遍历到节点数据: 10
遍历到节点数据: 20
✅ 17. list_for_each_entry_continue(pos, head, member)
📌 作用
继续从当前节点的下一个节点开始遍历。
🧾 参数
-
pos
:结构体类型指针; -
head
:链表头指针; -
member
:结构体中的list_head
成员名。
🧪 示例
// 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 = 10node2->data = 20node3->data = 30INIT_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 *poslist_for_each_entry(pos, &my_list, list){if (pos->data == 10)list_for_each_entry_continue(pos, &my_list, list)elseprintf("继续遍历到节点数据: %d\n", pos->data)}free(node1)free(node2)free(node3)return 0
}
📤 输出结果
继续遍历到节点数据: 20
继续遍历到节点数据: 30
✅ 18. list_for_each_entry_from(pos, head, member)
📌 作用
从指定节点 pos
开始继续遍历链表。
🧾 参数
-
pos
:结构体类型指针; -
head
:链表头指针; -
member
:结构体中的 `list_head` 成员名
🧪 示例
// 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 = 10node2->data = 20node3->data = 30INIT_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 *poslist_for_each_entry_from(pos, &my_list, list){printf("从指定节点继续遍历到节点数据: %d\n", pos->data)}free(node1)free(node2)free(node3)return 0
}
📤 输出结果
从指定节点继续遍历到节点数据: 10
从指定节点继续遍历到节点数据: 20
从指定节点继续遍历到节点数据: 30
✅ 19. list_for_each_entry_safe_reverse(pos, n, head, member)
📌 作用
安全地反向遍历链表,并删除节点。
🧾 参数
-
pos
:结构体类型指针; -
n
:临时指针; -
head
:链表头指针; -
member
:结构体中的list_head
成员名。
🧪 示例
// 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 = 10node2->data = 20node3->data = 30INIT_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, *nlist_for_each_entry_safe_reverse(pos, n, &my_list, list){printf("倒序遍历并删除节点数据: %d\n", pos->data)list_del(&pos->list)free(pos)}return 0
}
📤 输出结果
倒序遍历并删除节点数据: 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()
做的事。
🧪 示例
// 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 = 10node2->data = 20node3->data = 30INIT_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 = entrybreak}}// 从找到的节点后开始继续遍历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
}
✅ 输出结果:
从10之后继续遍历:
遍历数据: 20
遍历数据: 30
✅ 21. list_entry_is_head(ptr, head, member)
📌 作用
判断某个节点是否是链表的头节点。
换句话说:
它判断当前节点是否是链表头节点,在很多遍历时可以用来确认是否回到了链表头。
🧾 参数
-
ptr
:链表节点指针; -
head
:链表头指针; -
member
:链表结构体中的list_head
成员名。
🧪 示例
场景:遍历一个自定义结构体链表,打印所有节点的数据,并避免头节点被误处理。
#include <stdio.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/list.h>struct my_node {int datastruct list_head list
}int main()
{struct my_node headstruct my_node node1, node2INIT_LIST_HEAD(&head.list)node1.data = 1node2.data = 2list_add(&node1.list, &head.list)list_add(&node2.list, &head.list)struct my_node *poslist_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
}
🔎 宏定义分析
#define list_entry_is_head(pos, head, member) \(&pos->member == (head))
📤 输出结果
node: 2
This node is NOT head
node: 1
This node is NOT head
✅ 示例:演示 list_entry_is_head()
返回 true
#include <stdio.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/list.h>struct my_node {int datastruct 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
}