list_entry的宏定義:
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
這個(gè)倒是不難理解:從一個(gè)結(jié)構(gòu)的成員指針找到其容器的指針。
但是正因?yàn)槿绱耍业牡谝桓杏X是,這個(gè)宏的名字應(yīng)該更加抽象,名字似乎應(yīng)該改稱叫“尋找容器”一類的,查看list.h源代碼,發(fā)現(xiàn)現(xiàn)在的定義是這樣的:
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define container_of(ptr, type, member) \
({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);\
(type *)( (char *)__mptr - offsetof(type,member) ); \
})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
linux不想用C++,但又想利用C++的優(yōu)點(diǎn),如是出現(xiàn)了很多奇怪的宏,他們叫做trick。
ptr是找容器的那個(gè)變量的指針,把它減去自己在容器中的偏移量的值就應(yīng)該得到容器的指針。(容器就是包含自己的那個(gè)結(jié)構(gòu))。指針的加減要注意類型,用(char*)ptr是為了計(jì)算字節(jié)偏移。((type *)0)->member是一個(gè)小技巧。自己理解吧。前面的(type *)再轉(zhuǎn)回容器的類型。
=====================
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
ptr是指向list_head類型鏈表的指針,type為一個(gè)結(jié)構(gòu),而member為結(jié)構(gòu)type中的一個(gè)域,類型為list_head,這個(gè)宏返回指向type結(jié)構(gòu)的指針。在內(nèi)核代碼中大量引用了這個(gè)宏,因此,搞清楚這個(gè)宏的含義和用法非常重要。
設(shè)有如下結(jié)構(gòu)體定義:
typedef struct xxx
{
……(結(jié)構(gòu)體中其他域,令其總大小為size1)
type1 member;
……(結(jié)構(gòu)體中其他域)
}type;
定義變量:
type a;
type * b;
type1 * ptr;
執(zhí)行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
則可使b指向a,得到了a的地址。
如何做到的呢?
先看&((type *)0)->member:
把“0”強(qiáng)制轉(zhuǎn)化為指針類型,則該指針一定指向“0”(數(shù)據(jù)段基址)。因?yàn)橹羔樖恰皌ype *”型的,所以可取到以“0”為基地址的一個(gè)type型變量member域的地址。那么這個(gè)地址也就等于member域到結(jié)構(gòu)體基地址的偏移字節(jié)數(shù)。
再來看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):
(char *)(ptr)使得指針的加減操作步長為一字節(jié),(unsigned long)(&((type *)0)->member)等于ptr指向的member到該member所在結(jié)構(gòu)體基地址的偏移字節(jié)數(shù)。二者一減便得出該結(jié)構(gòu)體的地址。轉(zhuǎn)換為 (type *)型的指針,大功告成。
==============
list_entry定義如下:
/**
* 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) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
===================