開(kāi)門見(jiàn)山
offsetof
用于獲取結(jié)構(gòu)體成員的相對(duì)偏移,container_of
通過(guò)結(jié)構(gòu)體字段獲取結(jié)構(gòu)體地址。
offsetof
offsetof
的標(biāo)準(zhǔn)實(shí)現(xiàn)如下,其被定義在stddef.h
中:
#define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE?*)0)->MEMBER)
offsetof
宏的計(jì)算發(fā)生在編譯階段。
GCC
編譯器還為此提供一個(gè)內(nèi)置函數(shù)__builtin_offsetof
以提高編譯效率:
#define?offsetof(TYPE,?MEMBER)?__builtin_offsetof(TYPE,?MEMBER)
container_of
#define?container_of(ptr,?type,?member)?({??????????????????
????const?typeof(?((type?*)0)->member?)?*__mptr?=?(ptr);????
????(type?*)(?(char?*)__mptr?-?offsetof(type,member)?);})
typeof
是GCC
編譯器的一個(gè)擴(kuò)展,用于獲取變量或表達(dá)式的類型。在container_of
宏中,typeof( ((type *)0)->member )
用于獲取結(jié)構(gòu)體type
中成員member
的類型。
Linux
內(nèi)核實(shí)現(xiàn)中,為了更嚴(yán)格的類型檢查,和更好的符合C語(yǔ)言標(biāo)準(zhǔn),container_of
宏的實(shí)現(xiàn)如下:
#define?container_of(ptr,?type,?member)?({????
?void?*__mptr?=?(void?*)(ptr);?????
?static_assert(__same_type(*(ptr),?((type?*)0)->member)?||?
????????__same_type(*(ptr),?void),???
????????"pointer?type?mismatch?in?container_of()");?
?((type?*)(__mptr?-?offsetof(type,?member)));?})
static_assert
是C11
引入的靜態(tài)斷言機(jī)制,__same_type
由GCC
編譯器提供的內(nèi)置函數(shù)實(shí)現(xiàn)。
實(shí)際應(yīng)用
container_of
典型的應(yīng)用就是Linux
內(nèi)核中鏈表的實(shí)現(xiàn):
struct?list_head?{
?struct?list_head?*next,?*prev;
};
#define?list_entry(ptr,?type,?member)?
?container_of(ptr,?type,?member)
//?通過(guò)鏈表節(jié)點(diǎn)獲取節(jié)點(diǎn)所在結(jié)構(gòu),以下為示意,省略部分代碼
struct?my_struct?{
????int?a;
????char?b;
????struct?list_head?node;
};
struct?my_struct?data;
struct?my_struct?*entry?=?list_entry(&data,?struct?my_struct,?node)