正文
大家周末好,我是bug菌~ 今天主要是跟大家詳細(xì)聊聊container_of這個宏定義,非常經(jīng)典的宏,只是一直沒有抽時(shí)間細(xì)細(xì)品味,今天就跟大家一起來看看有何神奇之處:
1offsetof
首先我們需要簡單看看offsetof(TYPE, MEMBER) 這個宏定義,它是用于計(jì)算一個結(jié)構(gòu)體中某個成員的偏移量。
其第一個參數(shù) TYPE 是一個結(jié)構(gòu)體類型,第二個參數(shù) MEMBER 是 TYPE 中的一個成員變量名。
它將返回類型為 size_t 的整數(shù),表示 MEMBER 相對于 TYPE 起始地址的偏移量。
基本原理是根據(jù) C 語言的數(shù)據(jù)對齊機(jī)制,成員變量在類型定義中的相對位置決定了它的偏移量。
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
該宏定義使用了C語言中的指針運(yùn)算和類型轉(zhuǎn)換。具體實(shí)現(xiàn)步驟如下:
1、(TYPE *)0:將0強(qiáng)制類型轉(zhuǎn)換為指向類型為TYPE的指針,得到了一個結(jié)構(gòu)體TYPE的空指針。
2、&((TYPE *)0)->MEMBER:求出結(jié)構(gòu)體類型TYPE中成員MEMBER的地址。其巧妙之處在于,由于空指針不指向任何對象,因此這個成員的地址就是相對于結(jié)構(gòu)體首地址的偏移量。
3、(size_t):將偏移量轉(zhuǎn)換為無符號整型數(shù),以滿足C語言標(biāo)準(zhǔn)庫中對offsetof()返回值的類型要求。
該宏定義可以在編譯時(shí)就直接計(jì)算出偏移量,避免了運(yùn)行時(shí)的計(jì)算開銷,因此比通過變量名訪問成員的方式更為高效,通常用在需要直接訪問結(jié)構(gòu)體成員的底層代碼中,例如在操作系統(tǒng)內(nèi)核、嵌入式系統(tǒng)以及一些高性能計(jì)算應(yīng)用中。
structTestStruct{ intvalue1; charvalue2; doublevalue3; }; size_toffset=offsetof(structTestStruct,value2);
如上例,offset 變量將會存儲 value2 相對于 TestStruct 起始地址的偏移量。在這種情況下,因?yàn)?TestStruct 中的 value1 通常占用了 4 個字節(jié),value2 占用了 1 個字節(jié),所以 value2 相對于結(jié)構(gòu)體起始地址的偏移量應(yīng)該是 4。
2container_of
講完offsetof,來到今天的主角container_of,container_of()是一個在linux內(nèi)核中經(jīng)常使用的宏,用于獲取一個結(jié)構(gòu)體成員指針所在它所屬的結(jié)構(gòu)體的指針,有點(diǎn)繞口,細(xì)細(xì)品味。
該宏包括也主要包括三個參數(shù):
ptr:結(jié)構(gòu)體中某個成員的指針;
type:結(jié)構(gòu)體類型名稱;
member:結(jié)構(gòu)體中ptr指向的成員名稱。
首先,宏container_of()確定了ptr指向的成員在結(jié)構(gòu)體中的偏移(offset)。通過offsetof()宏就可以得到這個偏移,其參數(shù)為結(jié)構(gòu)體類型和成員名稱。得到偏移后,再通過減去偏移的方式得到指向整個結(jié)構(gòu)體的指針,巧妙吧。
具體實(shí)現(xiàn)如下:
#definecontainer_of(ptr,type,member)({ consttypeof(((type*)0)->member)*__mptr=(ptr); (type*)((char*)__mptr-offsetof(type,member));})
其中,typeof是GCC的一個擴(kuò)展關(guān)鍵字,用于返回一個表達(dá)式的類型,可惜,大部分非GCC編譯器不一定能支持。
假設(shè)ptr指向的成員變量的類型為T,__mptr就是一個指向T類型的指針。然后,調(diào)用offsetof()即可得到member在type類型中的偏移量,最后返回一個指向type類型的指針。
注意,尖括號不能省略,因?yàn)樗硎绢愋娃D(zhuǎn)換。此外,container_of()宏使用了一個GCC的語言擴(kuò)展"statement expression",即后面的{},可以在其中包含多條語句。
下面給出一個示例,用于說明container_of()的使用方法:
#include#include #definecontainer_of(ptr,type,member)({ consttypeof(((type*)0)->member)*__mptr=(ptr); (type*)((char*)__mptr-offsetof(type,member));}) structstudent{ intid; charname[20]; }; intmain(){ structstudentstu={10001,"ZhangSan"}; char*pname=stu.name; structstudent*pstu=container_of(pname,structstudent,name); printf("ID:%d,Name:%s ",pstu->id,pstu->name); return0; }
如上例,pname指向stu的name成員,通過container_of()宏獲得了指向整個struct student結(jié)構(gòu)體的指針pstu,然后就可以訪問id和name成員了。
審核編輯:湯梓紅
-
C語言
+關(guān)注
關(guān)注
180文章
7619瀏覽量
138719 -
結(jié)構(gòu)體
+關(guān)注
關(guān)注
1文章
130瀏覽量
10911 -
宏定義
+關(guān)注
關(guān)注
0文章
51瀏覽量
9083
原文標(biāo)題:搞懂它,就可以把結(jié)構(gòu)體玩活了~
文章出處:【微信號:最后一個bug,微信公眾號:最后一個bug】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
C語言宏定義使用技巧
Linux內(nèi)核中container_of原理詳解

這個奇怪的宏定義要干啥???
揭開linux內(nèi)核中container_of的神秘面紗
offsetof宏與container_of宏詳解
宏定義問題!
內(nèi)聯(lián)函數(shù)和宏定義的區(qū)別介紹

不帶參數(shù)的宏定義是什么?不帶參數(shù)的宏定義的資料介紹詳細(xì)過程概述
使用AVR單片機(jī)編寫的宏定義的應(yīng)用代碼詳細(xì)資料免費(fèi)下載

Linux內(nèi)核中的宏/container_of分析

c語言帶參數(shù)的宏定義
container_of()宏,太妙了~

評論