比較:
1.list_for_each和list_for_each_entry都是遍歷鏈表的兩個宏,本質上都是for循環。
2.他們做的事情本質上都一樣,A.獲取鏈表頭,B.判斷鏈表項是不是鏈表頭,C.指向鏈表的下一項。
3.他們的區別:list_for_each遍歷的鏈表,其鏈表項不屬於某個結構體。或者說不關心它是不是包含在某個結構體中。
list_for_each_entry遍歷的鏈表,其每一項都是某個結構體中的成員,單純遍歷鏈表還不行,還要找到包含這個
鏈表項的結構體的地址,從而為下一步應用該結構體做好准備。
一、list_for_each
list_for_each內核中的定義: /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)
一個簡單的for循環。
循環的初始化工作:pos指向鏈表頭的下一項。
循環的條件:pos不是鏈表頭。
每次循環要做的事情:pos指向鏈表中的下一項
二、list_for_each_entry
/** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member)*__mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member))
將for循環分解為一下三點:
1. for循環初始化 pos = list_entry((head)->next, typeof(*pos), member);
2. for循環執行條件 &pos->member != (head);
3. 每循環一次執行 pos = list_entry(pos->member.next, typeof(*pos), member))
解析:
1、(type *)0是一個強轉的操作,將0強行裝換成type類型的指針。
type類型是container_of的第二個參數,所以在使用container_of時第二個參數應該傳類型。
2、pos = list_entry((head)->next, typeof(*pos), member) , list_entry ---> container_of,因為list_entry第二個參數是typeof(* pos)。
typeof()是取變量的類型,這里是取指針pos所指向數據的類型
3、(type *)0)->member的作用就是得到成員變量member后,再通過typeof((type *)0)->member),就知道member成員的類型。
4、offsetof(type,member)是求出member在結構體中的偏移量,其中type是結構體的類型。
(char *)__mptr - offsetof(type,member)就是 __mptr - offset,即member類型的指針減去member在結構體中的偏移量。
一般__mptr = ptr,ptr是member的地址,那么member的地址減去member在結構體中偏移量不就是得到結構體的地址。
5、container_of的作用很明顯了 -- 獲得結構體的地址。
那么我們需要給他提供三個參數,分別是:ptr:member成員的指針 type:結構體類型 member:成員member的名字。
結構體pos中包含鏈表member,遍歷pos中的member成員。
pos: pos:
___________ ____________
| | | |
| | | |
| ........... | | ................ |
| | | |
| | | |
| member: | _________|__> member |
| { | | | { |
| *prev; | | | *prev; |
| *next;--|---------- | *next;-------------
| } | | } | |
|—^———— | |____________| |
| |
| |
|_____________________________________________|