((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->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)
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
ptr是指向list_head類型鏈表的指針,type爲一個結構,而member爲結構type中的一個域,類型爲list_head,這個宏返回指向type結構的指針。在內核代碼中大量引用了這個宏,因此,搞清楚這個宏的含義和用法非常重要。
設有如下結構體定義:
typedef struct xxx
{
……(結構體中其他域,令其總大小爲size1)
type1 member;
……(結構體中其他域)
}type;
定義變量:
type a;
type * b;
type1 * ptr;
執行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
則可使b指向a,得到了a的地址。
如何做到的呢?
先看&((type *)0)->member:
把“0”強制轉化爲指針類型,則該指針一定指向“0”(數據段基址)。因爲指針是“type *”型的,所以可取到以“0”爲基地址的一個type型變量member域的地址。那麼這個地址也就等於member域到結構體基地址的偏移字節數。
再來看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):
(char *)(ptr)使得指針的加減操作步長爲一字節,(unsigned long)(&((type *)0)->member)等於ptr指向的member到該member所在結構體基地址的偏移字節數。二者一減便得出該結構體的地址。轉換爲 (type *)型的指針,大功告成。
==============
/**
* 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)))