1,作用
原型container_of(ptr,type,member)。ptr是指向類型爲type的結構體中member元素的指針,該宏最終返回類型爲type的結構體的指針。
舉個例子,
struct my_struct{
int i;
int y;
};
struct my_struct A;
//這裏假設知道A中y變量的地址,求A的地址
int *ptr = &(A.y);
container_of(ptr,struct my_struct,y) //返回A的地址。
2,實現原理
1 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
2 #define container_of(ptr, type, member) ({ \
3 const typeof(((type *)0)->member) * __mptr = (ptr); \
4 (type *)((char *)__mptr - offsetof(type, member)); })
網上對這部分的分析已經比較多了,這裏不太詳述。大體是offsetof計算出member變量在type中的偏移量,container_of在ptr的基礎上減去偏移量獲得整個結構的基地址。3,若干問題
1,上述3行似乎無用,定義如下似乎也可以
#define container_of(ptr, type, member) ({ \
(type *)((char *)ptr - offsetof(type, member)); })
答曰:其實正常輸入來說,上述代碼同樣可以工作,第3行的主要作用在於類型檢測,阻止參數輸入錯誤的情況。這裏舉個例子來說明
#include <stdio.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#define container_of2(ptr, type, member) ({ \
(type *)((char *)ptr - offsetof(type, member)); })
struct my{
int i;
int y;
};
char k=0;
int main(){
struct my qq;
struct my *qqp;
qq.y=8;
printf("%p %p\n",&(qq.y),&qq);
qqp=container_of(&(qq.y),struct my,y); //OK
qqp=container_of2(&(qq.y),struct my,y);//OK
qqp=container_of(&k,struct my,y); //這裏會因爲參數不匹配而報錯
qqp=container_of2(&k,struct my,y); //沒有報錯,得到了一個錯誤的結果
return 0;
}
2 offsetof 中的地址0很容易理解,這樣可以很容易的計算出偏移量。但是第3行中的地址0怎麼理解呢?
答:由於使用了typeof,這裏僅僅時取得數據類型。typeof是GCC的擴展。關於typeof的使用,舉個例子
int *p;
typeof(*p) = int
於是typeof(((type *)0)->member)就是得到了type中member元素的類型。於是我的理解就是這裏僅僅是爲了取得數據類型,於是0的取值不重要,我改成了100,1000完全沒有影響。使用0估計是因爲用習慣了,總得有個數,要是隨便寫的話,也許引起的誤解會更多。自己的想法,和實驗的結果,歡迎指正。