container_of(ptr, type, member)宏的作用
該宏的作用是通過(guò)結(jié)構(gòu)體成員的地址和結(jié)構(gòu)體類(lèi)型推導(dǎo)出結(jié)構(gòu)體的地址,type是指結(jié)構(gòu)體的類(lèi)型,member是成員在結(jié)構(gòu)體中的名字,ptr是該成員在type結(jié)構(gòu)體中的地址。
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()
初學(xué)者可能會(huì)對(duì)其很陌生,所以我們要先從理解 offsetof(TYPE, MEMBER)
和 typeof()
的作用開(kāi)始。
offsetof(TYPE, MEMBER)
本質(zhì)也是個(gè)宏定義,在 linux 源碼的 toolsincludelinuxkernel.h
文件下定義如下:
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
offsetof
宏中的 TYPE
是指結(jié)構(gòu)體的類(lèi)型,MEMBER
是指結(jié)構(gòu)體中的某個(gè)成員,作用是求出該成員的在該結(jié)構(gòu)體中的偏移量。該宏首先將 0 (地址0)轉(zhuǎn)化為 TYPE *
的結(jié)構(gòu)體指針,表示地址為 0 的結(jié)構(gòu)體指針,然后通過(guò)取地址符 &((TYPE *)0)->MEMBER)
取出該結(jié)構(gòu)體指針中 MEMBER
成員的地址,最后再將地址值強(qiáng)轉(zhuǎn)為 size_t
類(lèi)型(內(nèi)核中為 unsigned long
類(lèi)型)即表示 MEMBER
成員在結(jié)構(gòu)體中的偏移量。要理解該過(guò)程需要了解對(duì)結(jié)構(gòu)體的內(nèi)存分布,如圖,結(jié)構(gòu)體的內(nèi)存分配是連續(xù)的,當(dāng)結(jié)構(gòu)體的地址為0時(shí),成員的地址即為該成員的偏移量。
實(shí)例:
#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實(shí)例結(jié)果輸出
typeof()
typeof()
是 GNU C
中的一個(gè)關(guān)鍵字,和 sizeof()
一樣都是 C 語(yǔ)言中的關(guān)鍵字而不是函數(shù)。作用是返回傳入數(shù)據(jù)的類(lèi)型。實(shí)例:
#include
intmain()
{
inta=3;
typeof(a)b=a;/*求出a變量的類(lèi)型,并創(chuàng)建一個(gè)b變量*/
printf("a=%db=%d",a,b);
return0;
}
輸出:
img
container_of(ptr, type, member)
了解了 offsetof()
宏和 typeof
關(guān)鍵字之后就比較好理解 container_of
宏的作用了。
consttypeof(((type*)0)->member)*__mptr=(ptr)
該代碼的作用實(shí)際上是將 0 轉(zhuǎn)化為 type *
結(jié)構(gòu)體類(lèi)型,再取出結(jié)構(gòu)體中的MEMBER成員 (type *)0)->member
, 再通過(guò) typeof
關(guān)鍵字獲取 MEMBER
成員的類(lèi)型,并定義一個(gè) MEMBER
成員類(lèi)型的指針 const typeof(((type *)0)->member) * __mptr
,將傳入的 ptr
指針賦值給 __mptr__mptr = (ptr)
。
(type*)((char*)__mptr-offsetof(type,member));
該代碼是將獲取的 MEMBER
成員地址強(qiáng)轉(zhuǎn)為 char *
(強(qiáng)轉(zhuǎn)的目的是考慮指針的加減的實(shí)質(zhì)是指針在內(nèi)存的偏移,偏移量為指針類(lèi)型所占字節(jié)的個(gè)數(shù)),減去 MEMBER
成員在 type
結(jié)構(gòu)體中的偏移量,強(qiáng)轉(zhuǎn)為 type *
后得到結(jié)構(gòu)體的地址。實(shí)例:
#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在實(shí)例結(jié)構(gòu)體中的地址結(jié)構(gòu)體類(lèi)型成員名*/
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
+關(guān)注
關(guān)注
87文章
11314瀏覽量
209777 -
源碼
+關(guān)注
關(guān)注
8文章
643瀏覽量
29265 -
結(jié)構(gòu)體
+關(guān)注
關(guān)注
1文章
130瀏覽量
10852
原文標(biāo)題:container_of()宏,太妙了~
文章出處:【微信號(hào):嵌入式情報(bào)局,微信公眾號(hào):嵌入式情報(bào)局】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論