1. 程式人生 > 實用技巧 >linux之list_for_each和list_for_each_entry函式

linux之list_for_each和list_for_each_entry函式

比較:
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;-------------
| } | |} | |
|—^———— | |____________| |
| |
| |
|_____________________________________________|