歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核中list_head、list_for_each、list_entry、container_of之間的關系

Linux內核中list_head、list_for_each、list_entry、container_of之間的關系

日期:2017/2/28 15:57:18   编辑:Linux內核
首先我們先看一下list_head的定義,該結構體在linux/types.h中定義。 [cpp]
  1. struct list_head {
  2. struct list_head *next, *prev;
  3. };

list_head很簡單,其實就是一個雙向鏈表,但是我們也許會奇怪,這樣的雙向鏈表能干什麼,它裡面連最起碼的一個泛化指針(void*)都沒有,也就是說我們不可能通過它來獲得其他對象的引用,那有什麼用呢?也許,讓我們來定義list_head,我們也許會這樣定義:

[cpp]

  1. struct hongchangfirst_list_head {
  2. struct list_head *next, *prev;
  3. void *general_pointer;
  4. };


這樣我們就可以隨心所欲的建立我們需要的任何數據結構的雙向鏈表了。但是Linux內核畢竟不是”一般人“寫出來的,所以人家就可以用剛才那種定義來實現任何數據結構的雙向鏈表,它是怎麼實現的呢?要明白這個問題,我們還得看看其它的一些結構體。

首先我們看一下list_for_each,它在linux/list.h中定義,我們可以看到它只是一個宏定義。

[cpp]
  1. #define list_for_each(pos, head) \
  2. for (pos = (head)->next; pos != (head); pos = pos->next)


其中head是list_head組成的雙向鏈表的指針,因為一般來說list_head雙向鏈表都是循環雙向鏈表,所以head就定義了你從哪裡開始遍歷這個鏈表,而pos就是指向list_head的指針,用來具體的對每一個list_head進行操作。用這個宏我們就可以實現對一個循環雙向鏈表的完整遍歷一遍。

如果只有這個遍歷又有什麼用呢,我們怎麼得到我們想要的相關數據結構引用呢?關鍵是我們還得有list_entry,它其實就是一個從list_head到一個擁有該list_head字段的“包含體”的入口宏定義,我們先看看這個宏定義,具體在linux/list.h中定義。

[cpp]
  1. #define list_entry(ptr, type, member) \
  2. container_of(ptr, type, member)

其實list_entry就是直接使用了container_of,那我們就得看看container_of 了,具體在linux/kernel.h裡定義。關於它的詳細理解請參考http://www.linuxidc.com/Linux/2012-02/53701.htm

[cpp]
  1. #define container_of(ptr, type, member) ({ \
  2. const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  3. (type *)( (char *)__mptr - offsetof(type,member) );})

其中ptr是指向包含體成員的指針,比如指向list_head的指針,type就是包含該成員(比如list_head字段)的”包含體“類型,member是該成員(比如list_head)在該包含體類型中具體的名字。它的返回值是一個指向type的指針。

Copyright © Linux教程網 All Rights Reserved