0.這是什么镊辕?有什么用掏婶?
Linux大神將雙向循環(huán)鏈表需要開(kāi)發(fā)者對(duì)鏈表基本操作函數(shù)的封裝逻炊,便于直接調(diào)用(復(fù)雜到用指針套了很多層指針,不過(guò)還有反轉(zhuǎn)等功能哦)
使用:#include "kernel_list.h"
struct kernel_list{//宿主
struct student std;
struct list_head myList;//包含兩個(gè)指針的(小)結(jié)構(gòu)體
}
內(nèi)核鏈表中封裝好的這些宏函數(shù)以及普通函數(shù)絕大部分都是在對(duì)小結(jié)構(gòu)體指針進(jìn)行操作
1.先上來(lái)個(gè)式子熱熱身
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
含義:
2.大結(jié)構(gòu)體(宿主)
小結(jié)構(gòu)體
使用時(shí)要處理小結(jié)構(gòu)體,操作小就能影響大
3.list_entry是什么
4.注意list_for_each的使用
list_for_each_entry:第一個(gè)參數(shù)不能傳錯(cuò)
參數(shù)代表意思很重要
list_for_each_entry_safe
例子:
//重點(diǎn):指定位置前插
int kernel_assign(struct kernel_list head ,struct kernel_list new ,char name){
struct kernel_list pos;
/list_for_each list_for_each_entry_safe/
list_for_each_entry(pos,&head->myList,myList){
if(strcmp(pos->stu.name,name)==0)
break;
}
//注意:這里的pos是大結(jié)構(gòu)體的,不能直接用
pos->myList.prev->next = &new->myList;
new->myList.next = &pos->myList;
new->myList.prev = pos->myList.prev;//與下面交換鹅心,連接會(huì)斷,轉(zhuǎn)換處理
pos->myList.prev = &new->myList;//本來(lái)在第三,連接會(huì)斷行拢,所以放第四
/list_add()又有什么不同/
return 0;
//什么時(shí)候會(huì)要pos.myList=pos.myList->next;
}
5.坑:static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)里三參數(shù)的解析
6.涉及知識(shí)點(diǎn):static inline(多次調(diào)用的且循環(huán)較少或無(wú)循環(huán)的函數(shù)焊傅,犧牲空間實(shí)現(xiàn)快速調(diào)用) & 宏定義(帶參數(shù))
7.相關(guān)參考
http://blog.chinaunix.net/uid-27037833-id-3237153.html
http://blog.csdn.net/tigerjibo/article/details/8299599
http://blog.csdn.net/coding__madman/article/details/51325646
所有的內(nèi)核鏈表的操作函數(shù)都是對(duì)小結(jié)構(gòu)體進(jìn)行操作的剂陡,不要錯(cuò)誤理解成大結(jié)構(gòu)體
(3)內(nèi)核鏈表的遍歷:
方法一:list_for_each()跟list_entry()相互配合實(shí)現(xiàn)遍歷
方法二:list_for_each_entry(pos, head, member) 將方法一的二個(gè)宏函數(shù)合并了
pos ---》大結(jié)構(gòu)體指針
head ---》小結(jié)構(gòu)體指針
member ---》小結(jié)構(gòu)體在大結(jié)構(gòu)體中的名字
注意:第一個(gè)參數(shù)一定不要傳參錯(cuò)誤,是大結(jié)構(gòu)體
方法三:list_for_each_entry_safe(pos, n, head, member) 往往在刪除節(jié)點(diǎn)的時(shí)候使用
pos ---》大結(jié)構(gòu)體指針
n ---》大結(jié)構(gòu)體指針
head ---》小結(jié)構(gòu)體指針
member ---》小結(jié)構(gòu)體在大結(jié)構(gòu)體中的名字
(4)刪除
list_for_each_entry_safe(pos, n, head, member)
list_del(struct list_head *entry)
entry ---》你想要?jiǎng)h除的那個(gè)節(jié)點(diǎn)里面的小結(jié)構(gòu)體指針
(5)list_move(struct list_head *list,
struct list_head *head)
list_move() ---》將指定的節(jié)點(diǎn)移動(dòng)到head的下一個(gè)位置
list_move_tail()---》將指定的節(jié)點(diǎn)移動(dòng)到最后面
(6)container_of(ptr, type, member) 求ptr對(duì)應(yīng)的大結(jié)構(gòu)體
雖然內(nèi)核鏈表沒(méi)有給我們封裝指定位置插入的函數(shù)狐胎,但是你可以自己去寫鸭栖,注意使用的指針是小結(jié)構(gòu)體里面的next和prev
總結(jié):(1)經(jīng)過(guò)反復(fù)使用內(nèi)核鏈表,加上分析了源碼握巢,我們發(fā)現(xiàn)內(nèi)核鏈表跟前面學(xué)的雙向循環(huán)鏈表的操作模式是類似的晕鹊,只是要注意內(nèi)核鏈表是操作的小結(jié)構(gòu)體指針,所有在指針的寫法上變得很啰嗦(自己體會(huì)暴浦,查看我寫的最終代碼)
(2)內(nèi)核鏈表中封裝的那個(gè)小結(jié)構(gòu)體一般都寫成普通結(jié)構(gòu)體溅话,注意在使用的時(shí)候取地址