通常實現雙向鏈表的數據結構:
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語言中直接操作內存地址的特性。