通常實現雙向鏈表的資料結構:
struct list_node1{ struct list_node1 *next,*prev; type1 m1; type2 m2;};struct list_node2{ struct list_node2 *next,*prev; type1 m1; type2 m2;};……
對於每一種資料結構都定義了其特定的實現鏈表的結構和對應的方法(add/del)操作鏈結表;
但對於具有大量不同資料結構,都要使用鏈表的系統中,如果為每一種資料結構定義特定的結構,和操作方法,
無疑使代碼變得重複和臃腫,需要實現一種通用的雙向鏈表方法,對各種資料結構都能適用。
C語言中又沒有C++裡面的模板,該如何?呢?
linux核心中大量使用如下資料結構實現雙向鏈表:
struct list_head { struct list_head *next, *prev;};
如果需要有某種資料結構的雙向隊列,就在這種結構內部放一個list_head資料結構成員。
struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset;}
形成了如下結構:
如何通過kobject 鏈表結構中的 list_head 成員entry訪問下一個成員呢?
系統提供了宏list_entry:
#define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
//訪問鏈表成員kobject *obj = objList;kobject *nextObj = (kobject *)list_entry(obj->entry->next,struct kobject,entry);
這個list_entry是什麼道理呢:
ptr:是指向當前kobject結構對象中的資料成員entry,(char *)(ptr):entry成員地址 ——AddrA;
(unsigned long)(&((type *)0)->member)):將地址0轉化為類型為type(struct kobject )對象,取member(entry)成員的地址——AddrB。
(type *)(AddrA - AddrB):得到kobject結構對象的首地址,轉化為kobject對象。
這裡需要關注的就是AddrB:將地址0轉化為類型為type(struct kobject )對象,取member(entry)成員的地址。
表示當struct kobject 對象首地址為0時,得到成員member(entry)的地址,相對首地址的位移地址。
通過struct kobject 對象中member(entry)的地址 ,以及相對首地址的位移量,就能計算出struct kobject 對象的首地址。
如下結構:
充分利用了C語言中直接操作記憶體位址的特性。