详解两个重要宏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一样
}


(原创,如转载,请说明本文出处)






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值