根據結構體變量地址反推結構體首地址

最近在看《Linux內核設計與實現》這本書,感受寫得很是棒,看第6章《內核數據結構》的時候,遇到兩個很是牛B的宏,據此簡單地設計一個考題,以便分析它們。linux

    

【題目】:微信

根據一個結構體某成員的名稱和地址,以及結構體的類型,計算出該結構體對象的首地址。數據結構

    

【例如】:學習

struct A   
{   
    int x;   
    int y;   
    int z;   
}   
   
#define GET_HEADER_ADDR(MEMBER_NAME,MEMBER_ADDR,STRUCT_TYPE) (你來實現)  
   
void main()   
{   
    struct A myTest;   
   
    int *pz = &myTest.z;  
   
    printf("addr is %d",GET_HEADER_ADDR(z,pz,struct A) );   
   
}

    

不看下面的答案,你來嘗試實現上面這個宏吧。.net

 

    

【答案與分析過程】設計

    

Linux內核中,用兩個很是巧妙地宏實現了,一個是offsetof宏,另外一個是container_of宏,下面講解一下這兩個宏。指針

 

1. offsetof宏對象

【定義】:#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )get

【功能】: 得到一個結構體變量成員在此結構體中的偏移量。編譯器

【例子】: 

 

struct A 
{ 
    int x ; 
    int y; 
    int z; 
}; 
 
void main() 
{ 
    printf("the offset of z is %d",offsetof( struct A, z )  ); 
} 
 
// 輸出結果爲 8

【分析】:

 

該宏,TYPE爲結構體類型,MEMBER 爲結構體內的變量名。

 

(TYPE *)0) 是欺騙編譯器說有一個指向結構TYPE 的指針,其地址值0 

 

(TYPE *)0)->MEMBER 是要取得結構體TYPE中成員變量MEMBER的地址. 由於基址爲0,因此,這時MEMBER的地址固然就是MEMBER在TYPE中的偏移了。

 

2. container_of宏(即實現了題目中的功能)

 

【定義】:

 

#define container_of(ptr, type, member)   ({const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})

 

【功能】:

 

從結構體(type)某成員變量(member)指針(ptr)來求出該結構體(type)的首指針。

 

【例子】:

 

 

struct A 

   int x ; 
   int y; 
   int z; 
}; 

struct A myTest; 

int *pz = &myTest.z; 

struct A* getHeaderPtr( int *pz ) 

   return container_of( pz , struct A, z ); 

 

【分析】:

 

(1) typeof( ( (type *)0)->member )爲取出member成員的變量類型。

(2) 定義__mptr指針ptr爲指向該成員變量的指針(即指向ptr所指向的變量處)


(3) (char *)__mptr - offsetof(type,member)) 用該成員變量的實際地址減去該變量在結構體中的偏移,來求出結構體起始地址。


(4) ({ })這個擴展返回程序塊中最後一個表達式的值。

 

結束語

 

免費學習更多精品課程,登陸樂搏學院官網http://h.learnbo.cn/

或關注咱們的官方微博微信,還有更多驚喜哦~

相關文章
相關標籤/搜索