本文解析关于结构体的两个重要宏
offsetof( TYPE , MEMBER)和
container_of(ptr , type , member)
实例1、#define offsetof( TYPE , MEMBER)
(int *)&((TYPE *)0)->MEMBER
(备注:
->的优先级比&高)
参数说明:TYPE为结构体变量类型;MEMBER为结构体中任意一个元素
作
用:得出该MEMBER元素相对于结构体首地址的偏移量
分层解析:
实
质:将结构体变量地址强制变成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为结构体中任意一个元素
作
用:通过结构体中某一元素的地址得出结构体(变量)首(的)地址;
分层解析:
实
质:当传参数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一样
}
(原创,如转载,请说明本文出处)