当前位置: 首页 > news >正文

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)

📌 作用

初始化一个已经定义好的链表头指针,确保其 nextprev 都指向自身,形成一个空的循环链表。

🧾 参数
  • 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()

  • 删除后,该节点的 nextprev 不会自动清空(可选使用 list_del_init() 初始化)。

    list_del(&node1->list) 删除了 node1 节点,但是 node1->list.prevnode1->list.next 依然保留了原来的值。它们指向链表中曾经链接到 node1 的节点。因此,删除后的节点仍然有 nextprev 指针,它们并没有被清空。

    list_del_init() 也用于从链表中删除节点,它不仅删除节点,还将被删除节点的 nextprev 指针设置为链表头节点的指针(即初始化节点)。这通常用于防止误用已经删除的节点。


🧪 示例
// 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 == headhead->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 节点指针(不自动转换为结构体)。

🧾 参数
  • posstruct 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 相对,后者从链表头开始向后遍历。

🧾 参数
  • posstruct 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
}

相关文章:

  • 前端开发实战:用React Hooks优化你的组件性能
  • 缓存理论到实战:技术选型与七层架构设计
  • Windows 系统 - Trae 内 终端 无法使用 node (重新配置 nodejs 路径)
  • RT-Thread 深入系列 Part 7:RT-Thread vs 其他 RTOS 对比与选型指南
  • 图像处理篇---opencv实现坐姿检测
  • Kotlin高阶函数多态场景条件判断与子逻辑
  • 腾讯多模态定制化视频生成框架:HunyuanCustom
  • C语言的中断 vs Java/Kotlin的异常:底层机制与高级抽象的对比
  • android HashMap和List该如何选择
  • 05 mysql之DDL
  • 通俗的理解MFC消息机制
  • 基于小波神经网络(WNN)的回归预测模型【MATLAB】
  • Flutter PIP 插件 ---- 为iOS 重构PipController, Demo界面,更好的体验
  • 大学之大:悉尼科技大学2025.5.10
  • 在 Flink + Kafka 实时数仓中,如何确保端到端的 Exactly-Once
  • 分布式锁原理
  • 自主shell命令行解释器
  • 北斗终端设备应用
  • Vue3组件通信 emit 的工作原理
  • CUDA编程——性能优化基本技巧
  • 体验中国传统文化、采购非遗文创,波兰游客走进上海市群艺馆
  • 第三届“老山国际春茶节”活动在云南麻栗坡举办
  • 北京2025年住房发展计划:供应商品住房用地240-300公顷,建设筹集保租房5万套
  • 上海市委常委会会议暨市生态文明建设领导小组会议研究基层减负、生态环保等事项
  • 国办印发《关于进一步加强困境儿童福利保障工作的意见》
  • 古埃及展进入百天倒计时,闭幕前168小时不闭馆