container_of(ptr, type, member)宏的作用
該宏的作用是通過結構體成員的地址和結構體類型推導出結構體的地址,type是指結構體的類型,member是成員在結構體中的名字,ptr是該成員在type結構體中的地址。
container_of(ptr, type, member)宏解析
在 linux 源碼的 toolsincludelinuxkernel.h
文件下,container_of()
的定義如下:
#ifndefcontainer_of
/**
*container_of-castamemberofastructureouttothecontainingstructure
*@ptr:thepointertothemember.
*@type:thetypeofthecontainerstructthisisembeddedin.
*@member:thenameofthememberwithinthestruct.
*
*/
#definecontainer_of(ptr,type,member)({
consttypeof(((type*)0)->member)*__mptr=(ptr);
(type*)((char*)__mptr-offsetof(type,member));})
#endif
在 container_of()
宏的定義中的 offsetof(TYPE, MEMBER)
和 typeof()
初學者可能會對其很陌生,所以我們要先從理解 offsetof(TYPE, MEMBER)
和 typeof()
的作用開始。
offsetof(TYPE, MEMBER)
本質也是個宏定義,在 linux 源碼的 toolsincludelinuxkernel.h
文件下定義如下:
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
offsetof
宏中的 TYPE
是指結構體的類型,MEMBER
是指結構體中的某個成員,作用是求出該成員的在該結構體中的偏移量。該宏首先將 0 (地址0)轉化為 TYPE *
的結構體指針,表示地址為 0 的結構體指針,然后通過取地址符 &((TYPE *)0)->MEMBER)
取出該結構體指針中 MEMBER
成員的地址,最后再將地址值強轉為 size_t
類型(內核中為 unsigned long
類型)即表示 MEMBER
成員在結構體中的偏移量。要理解該過程需要了解對結構體的內存分布,如圖,結構體的內存分配是連續的,當結構體的地址為0時,成員的地址即為該成員的偏移量。
實例:
#include
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
typedefstruct_offset
{
charmember_0;
intmember_1;
charmember_2;
}offset;
intmain()
{
printf("%d
",offsetof(offset,member_0));
printf("%d
",offsetof(offset,member_1));
printf("%d
",offsetof(offset,member_2));
return0;
}
輸出:
offsetof實例結果輸出
typeof()
typeof()
是 GNU C
中的一個關鍵字,和 sizeof()
一樣都是 C 語言中的關鍵字而不是函數。作用是返回傳入數據的類型。實例:
#include
intmain()
{
inta=3;
typeof(a)b=a;/*求出a變量的類型,并創建一個b變量*/
printf("a=%db=%d",a,b);
return0;
}
輸出:
img
container_of(ptr, type, member)
了解了 offsetof()
宏和 typeof
關鍵字之后就比較好理解 container_of
宏的作用了。
consttypeof(((type*)0)->member)*__mptr=(ptr)
該代碼的作用實際上是將 0 轉化為 type *
結構體類型,再取出結構體中的MEMBER成員 (type *)0)->member
, 再通過 typeof
關鍵字獲取 MEMBER
成員的類型,并定義一個 MEMBER
成員類型的指針 const typeof(((type *)0)->member) * __mptr
,將傳入的 ptr
指針賦值給 __mptr__mptr = (ptr)
。
(type*)((char*)__mptr-offsetof(type,member));
該代碼是將獲取的 MEMBER
成員地址強轉為 char *
(強轉的目的是考慮指針的加減的實質是指針在內存的偏移,偏移量為指針類型所占字節的個數),減去 MEMBER
成員在 type
結構體中的偏移量,強轉為 type *
后得到結構體的地址。實例:
#include
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
#ifndefcontainer_of
#definecontainer_of(ptr,type,member)({
consttypeof(((type*)0)->member)*__mptr=(ptr);
(type*)((char*)__mptr-offsetof(type,member));})
#endif
typedefstruct_container
{
charmember_0;
intmember_1;
charmember_2;
}container;
intmain(void)
{
container*a=NULL;
containerb={'a',2,'b'};
/*member_1在實例結構體中的地址結構體類型成員名*/
a=container_of(&b.member_1,container,member_1);
printf("a->member_0=%c
",a->member_0);
printf("a->member_1=%d
",a->member_1);
printf("a->member_2=%c
",a->member_2);
return0;
}
輸出:
-
Linux
+關注
關注
87文章
11229瀏覽量
208928 -
源碼
+關注
關注
8文章
633瀏覽量
29140 -
結構體
+關注
關注
1文章
130瀏覽量
10833
原文標題:container_of()宏,太妙了~
文章出處:【微信號:嵌入式情報局,微信公眾號:嵌入式情報局】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論