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;
}
輸出:

typeof()
typeof() 是 GNU C 中的一個關鍵字,和 sizeof() 一樣都是 C 語言中的關鍵字而不是函數。作用是返回傳入數據的類型。實例:
#include
intmain()
{
inta=3;
typeof(a)b=a;/*求出a變量的類型,并創建一個b變量*/
printf("a=%db=%d",a,b);
return0;
}
輸出:

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
+關注
關注
88文章
11760瀏覽量
219016 -
源碼
+關注
關注
8文章
685瀏覽量
31319 -
結構體
+關注
關注
1文章
131瀏覽量
11372
原文標題:container_of()宏,太妙了~
文章出處:【微信號:嵌入式情報局,微信公眾號:嵌入式情報局】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
詳細聊聊container_of這個宏定義
揭開linux內核中container_of的神秘面紗
Labview Active Container引用AUTODESK控件后異常?
鴻蒙應用開發-container動漫效果體驗
Linux內核中的C語言語法擴展
請教一下大神內核源碼中的containerof該怎樣去實現呢
RT-Thread中侵入式鏈表的應用有哪些呢
Linux內核基礎-container_of
Accelerated Container Image基于塊設備的容器鏡像加速服務
Missing Container Metrics容器指標收集工具
Linux內核中的宏/container_of分析
container_of()宏,太妙了~
評論