詳解兩個重要宏offsetof和containe…
本文解析關於結構體的兩個重要宏offsetof(
TYPE , MEMBER)和container_of(ptr ,
type , member)
實例1、#define offsetof( TYPE ,
MEMBER) (int *)&((TYPE
*)0)->MEMBER
(備註:
->的優先級比&高)
參數說明:TYPE爲結構體變量類型;MEMBER爲結構體中任意一個元素
作
用:得出該MEMBER元素相對於結構體首地址的偏移量
分層解析:
(1)
((TYPE*)0):將0強制轉換成指向TYPE類型結構體變量的指針,該結構體變量地址被強制變爲0x0;
(2)
((TYPE*)0)->MEMBER:指向結構體中的MEMBER元素;
(3)
(int *)&((TYPE *)0)->MEMBER:取MEMBER元素的地址並強制轉換成指向int類型數據的指針。
實
質:將結構體變量地址強制變成0x0,當得出其中某個元素地址後,由於結構體內元素地址是邏輯連續的,該元素地址被強制轉換成(int
*)後即可被理解爲偏移量。(見代碼示例1)
實例2、#define container_of(ptr , type , member) ({
const typeof(((type *)0)->member) *__mptr =
(ptr) ; (type *)((char *)__mptr - offsetof(type , member ) );
})
參數說明:ptr爲指向member元素的指針;type爲結構體變量類型;member爲結構體中任意一個元素
作
用:通過結構體中某一元素的地址得出結構體(變量)首(的)地址;
分層解析:
(1)
typeof(((type *)0)->member)得出member元素的數據類型;
(2)
const typeof(((type *)0)->member)
*__mptr定義一個和member同數據類型的指針,指針指向常量;
(3) __mptr = (ptr)
將指向member元素的指針賦給新定義的__mptr指針;
(4)
(char *)__mptr - offsetof(type , member
)該元素地址減去自身相對結構體地址偏移量得出初始地址;
(5) (type *)((char *)__mptr - offsetof(type ,
member ) )將初始地址強制轉換成結構體變量地址。
實
質:當傳參數ptr指針時,編譯器只傳ptr的值,並沒傳它的數據類型,所以需要通過typeof()函數獲取它的類型;得出member元素的地址和類型後,減去它的偏移量,即可得出初始地址,即爲結構體首地址。(見代碼示例2)
代碼示例(1)
#include
#define offset(TYPE,MEMBER) ((int)&(((TYPE
*)0)->MEMBER))
struct mystruct
{
char a;
};
int main ( )
{
struct mystruct s1;
int offsetof_a = offset(struct mystruct,a);
printf("offsetof_a = %d\n",offsetof_a);
}
代碼示例(2)
#include
#define offsetof(TYPE,MEMBER)
((int)&(((TYPE *)0)->MEMBER))
//算結構體中元素的地址偏移量
#define container_of(ptr,type,member) ({
const typeof(((type *)0)->member) *__mptr = (ptr);\
(type *)((char *)__mptr - offsetof(type,member));
}) //得出結構體首地址
// 宏定義中'\'表示連接上下行
struct mystruct
{
char a;
short c;
};
int main ()
{
struct mystruct s1;
struct mystruct *p = NULL;
short *p1 = &s1.c;
printf("s1的指針 = %p\n",&s1);
//此句可得到結構體首地址,前提是定義了變量s1;
//但在Linux內核中,往往不知道結構體變量的,那該如何得到呢?請看下面
//現在要通過p來計算得到s1的指針
p1 = container_of(p,struct mystruct,c);
printf("ps的指針 = %p\n",p1);
//地址值和&s1一樣
}
(原創,如轉載,請說明本文出處)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.