在嵌入式中,一般涉及到Linux内核代碼的時候,會遇到typeof(注意不是typedef)和container_of,本文使用代碼方式介紹typeof關鍵字和container_of宏。
一、typeof“關鍵字”
在ANSI C标準中定義了sizeof關鍵字用于獲取變量和數據類型在内存中所占的字節數。GNU C中又擴展了typeof“關鍵字”,用于獲取變量或表達式的類型。typeof是gcc标準,目前尚未納入C标準。如下,代碼使用介紹:
(typeof代碼)
(gcc編譯運行)
由此可知,通過typeof獲取變量的類型後,可以使用該類型再定義一個變量。
typeof(m) n = 6相當于
int n = 6;
如此看來,typeof并沒有什麼新奇的?但如果配合下面的container_of宏,效果就顯著多了。
二、container_of宏有了typeof的基礎,直接在查看該宏的真面目:
container_of的定義
上述就是該宏的真面目,可以說設計的相當巧奪天工。這個宏的主要作用:根據結構體某一成員的地址,獲取這個結構體的首地址。該宏需要三個元素:ptr為結構體成員member的地址,member為結構體的成員,type為結構體類型。
上述描述比較幹澀,直接上代碼調試(使用自定義的CONTAINER_OF):
container_of代碼示例
container_of運行
從上述看,僅需要知道原結構體的一個成員team.number,可以推導原結構體的地址team,自然就可以獲取該結構體其他成員的值。
實際使用的情況:假如傳給某個函數的參數是某個結構體的成員變量,但是在這個函數中可能還需要使用到該結構體的其他成員變量,那麼這時候使用container_of就非常方便。
一個結構體數據類型,在相同編譯環境下,各個成員相對于結構體首地址的偏移是固定不變的。即當結構體的首地址為0時,結構體中各個成員的地址在數值上等于結構體成員相對于結構體首地址的偏移。
仔細分析:
#define OFFSET_OF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)。結構體類型TYPE和結構體TYPE的成員MEMBER,将0強制轉化為一個指向TYPE類型的結構體常量,然後通過這個常量指針房屋成員,獲取MEMBER的地址,它的大小在數值上等于MEMBER成員在結構體TYPE中的偏移。
如何獲取ptr指針類型,即通過(typeof的使用):
typeof( ((type *)0)->member ) *__mptr = (ptr)方式獲取。
至此,typeof與container_of的基本介紹完畢。
,