標籤:
首先來個簡單版本
1 /* given a pointer @ptr to the field @member embedded into type (usually2 * struct) @type, return pointer to the embedding instance of @type. */3 #define container_of(ptr, type, member) 4 ((type *)((char *)(ptr)-(char *)(&((type *)0)->member)))
作用:主要用於結構體,給定一個指標ptr指向一個結構體type的執行個體的成員member,返回此結構體執行個體的首地址,也就是這個結構體執行個體的指標,囉嗦一堆,還不如一個執行個體:
1 typedef struct ABC{ 2 char a; 3 char b; 4 int c; 5 }ABC; 6 7 int main(int argc, const char *argv[]) 8 { 9 ABC ins;10 11 printf("%p\n", container_of(&ins.c, ABC, c));12 printf("%p\n", &ins);13 return 0;14 }
列印出來的值應該是相等的,都是結構體ins的首地址。我們將宏展開:
container_of(&ins.c, ABC, c);//展開後((ABC *)((char *)(&ins.c)-(char *)(&((ABC *)0)->c)));
在減號的2邊分別是2個部分,前面: (char *)(&ins.c),也就是指向ins的成員c的指標,後面:(char *)( &(((ABC *)0)->c))就是成員c相對於結構體ABC指標的位移,比如在本例中:
成員c的指標(&ins.c)減去成員c的位移(offset)那麼得到的就是結構體ins首地址。如果我只知道某個結構體成員的指標值,那麼通過container_of宏就可以得到結構體指標,那麼就可以隨意訪問它的任意一個成員。
升級版:
1 #define offsetof(typ,memb) ((long)(long_ptr_t)((char *)&(((typ *)0)->memb)))2 #define container_of(ptr, type, member) ({ 3 const typeof( ((type *)0)->member ) *__mptr = (ptr); 4 (type *)( (char *)__mptr - offsetof(type,member) );})
升級版有何改進呢?我就我知道的總結下:
1.const修飾,確保傳入的ptr指向不被修改。2.使用了一個中間變數,定義一個成員member類型的變數指標__mptr,然後將ptr賦值給它。為何要這樣?就是為了以防萬一,如果你搞錯了傳的指標不是指向成員member的,那麼編譯器至少會有個警告。
3.offset宏使用(long)(long_ptr_t)2個資料類型作強轉我沒看太懂,(long long )64位?一個成員的位移有可能超過32位?倒是__mptr這個地址值可能超過32位(定址超過4G)。不解。
參考:
http://broken.build/2012/11/10/magical-container_of-macro/
linux 3.13.0核心。
linux核心宏container_of