🔧 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
}