經過結構體總體變量來訪問其中各個元素,本質上是經過指針方式來訪問的,形式上是經過.的方式來訪問的(這時候實際上是編譯器幫咱們自動計算了偏移量)。
linux
1:offset_of宏ide
做用:計算結構體中某個元素和結構體首地址的偏移量(其實質是經過編譯器來幫咱們計算)。spa
定義:
指針
#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
參數分析:TYPE是結構體類型,MEMBER是結構體中一個元素的元素名編譯器
返回值:member元素相對於整個結構體變量的首地址的偏移量,類型是intit
原理:經過虛擬一個type類型結構體變量,而後用type.member的方式來訪問那個member元素,繼而獲得member相對於整個變量首地址的偏移量。編譯
(TYPE *)0 這是一個強制類型轉換,把0地址強制類型轉換成一個指針,這個指針指向一個TYPE類型的結構體變量。 (實際上這個結構體變量可能不存在,可是隻要我不去解引用這個指針就不會出錯)。class
((TYPE *)0)->MEMBER (TYPE *)0是一個TYPE類型結構體變量的指針,經過指針來訪問這個結構體變量的member元素變量
&((TYPE *)0)->MEMBER 等效於&(((TYPE *)0)->MEMBER),意義就是獲得member元素的地址。可是由於整個結構體變量的首地址是0,因此member元素的地址就是member元素相對於整個結構體的偏移量原理
2:container_of宏:
container_of宏是linux內核中經常使用的一個宏,用於從結構體元素中獲取這個結構體本質的指針,也就是經過結構體變量中的某個成員變量來獲取整個結構體的首地址
container_of宏定義以下
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
分析:
(1)做用:知道一個結構體中某個元素的指針,反推這個結構體變量的指針。有 了container_of宏,咱們能夠從一個元素的指針獲得整個結構體變量的指針,繼而獲得結構體中其餘元素的指針。
(2)typeof關鍵字的做用是:typepof(a)時由變量a獲得a的類型,typeof就是由變量名獲得變量數據類型的。
(3)這個宏的工做原理:先用typeof獲得member元素的類型定義成一個指針,而後用這個指針減去該元素相對於整個結構體變量的偏移量(偏移量用offsetof宏獲得的),減去以後獲得的就是整個結構體變量的首地址了,再把這個地址強制類型轉換爲type *便可。