例說Linux核心鏈表(三),linux核心
常用的linux核心雙向鏈表API介紹
linux link list結構圖如下:
核心雙向鏈表的在linux核心中的位置:/include/linux/list.h
使用雙向鏈表的過程,主要過程包括建立包含struct link_head結構的結構體(item),建立鏈表頭,向鏈表中添加item(自訂資料結構,雙向鏈表資料單元),刪除鏈表節點,遍曆鏈表,判空等。
1、建立自訂鏈表資料結構
- struct kool_list{
- int to;
- struct list_head list; //包含鏈表頭
- int from;
- };//自訂欲連結的資料額結構,並包含雙向鏈表結構
2、建立鏈表頭
- struct kool_list mylist;
- INIT_LIST_HEAD(&mylist.list);//初始化一個鏈表表頭
-
或者
static LIST_HEAD(adc_host_head);//初始化一個鏈表頭adc_host_head
第二種建立鏈表頭和第一種的區別在於,第二種在編譯的時候才會被初始化。還有一點就是鏈表頭是獨立的還是位於自訂鏈表資料結構中的。就好比在《例說Linux核心鏈表(二)》中給出的鏈表結構圖和本文給出的結構圖的區別。
3、向鏈表添加item
list_add(struct list_head *new, struct list_head *head);
例如:
- struct kool_list *tmp;
- tmp= (struct kool_list *)malloc(sizeof(struct kool_list));
-
- printf("enter to and from:");
- scanf("%d %d", &tmp->to, &tmp->from); //初始化資料結構
- /* add the new item 'tmp' to the list of items in mylist */
- list_add(&(tmp->list), &(mylist.list));//項鏈表中添加新的元素節點,tmp中的list
list_add_tail(struct list_head *new, struct list_head *head);
在鏈表的尾部添加一個item,和list_add的區別在於,list_add把新的item加到了鏈表頭的後面,list_add_tail把item加到了鏈表頭的前面。
4、遍曆鏈表
list_for_each_entry(type *cursor, struct list_head *list, member)
這並不是一個函數,它是一個for迴圈,依次列出要遍曆的鏈表,三個元素代表的意義:type *cursor代表item的指標,struct list_head *list是鏈表頭,member是item中包含的list_head資料項目。通過這三個資料可以定位到鏈表的每一個資料元素。其中定位原理就是結構體位移。
例如:
- list_for_each_entry(tmp, &mylist.list, list)
- printf("to= %d from= %d\n", tmp->to, tmp->from);
這個宏可以分為兩步,第一步是遍曆鏈表,pos依次指向鏈表中每個item的struct list_head 結構,第二步是擷取pos指向的struct list_head所在的item。這裡是tmp 。
list_for_each(pos, &mylist.list){//遍曆鏈表,pos依次指向鏈表的元素
tmp= list_entry(pos, struct kool_list, list);//獲得包含pos節點的資料結構指標
5、刪除
刪除鏈表中的某節點,首先要使用安全遍曆,然後再刪除。
例如:
- list_for_each_safe(pos, q, &mylist.list){
- tmp= list_entry(pos, struct kool_list, list);
- printf("freeing item to= %d from= %d\n", tmp->to, tmp->from);
- list_del(pos);
6、鏈表空
int list_empty(struct list_head *head);
Returns a nonzero value if the given list is empty.
參考網站:http://www.makelinux.net/ldd3/chp-11-sect-5
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。