获取结构体成员的偏移量offsetof()以及containerof()函数

144 篇文章 6 订阅

前言

在linux 内核中,container_of 函数使用非常广,例如 linux内核链表 list_head、工作队列work_struct中。其实它的语法很简单,只是一些指针的灵活应用,它分两步:

      第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。

      第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。

那这个宏到底是用来干嘛的呢?我们先来看看它在内核中是怎样定义的。

呵呵,乍一看不知道是什么东东。

我们先来分析一下container_of(ptr,type,member) ,这里面有ptr,type,member分别代表指针、类型、成员。

看一个例子:

1

2

3

4

5

6

7

Struct test

  {

    int i;

    int j;

    char k;

  };

  Struct test temp;

现在呢如果我想通过temp.j的地址找到temp的首地址就可以使用container_of(&temp.j,struct test,j);

现在我们知道container_of()的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。

下面来看看比较复杂的内容:

我们用上面的struct test张展一下

1

Const typeof(((struct test *)0)->j) * __mptr = (&temp.j); //(sturct test *)0 表示数据段基址

其中,typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型。因此,上述代码的作用是首先使用typeof获取结构体成员j的类型为int,然后顶一个int指针类型的临时变量__mptr,并将结构体变量中的成员的地址赋给临时变量__mptr

1

(struct test *)((char *)__mptr - offsetof(struct test,j));

接着我们来看一下offsetof(struct test,j) ,他在内核中如下定义

展开(size_t)&((struct test *)0)->j ,这是什么东东?

一开始也不明白,这里要感谢曹忠明老师的热心帮助,一语惊醒梦中人,呵呵,可以是这样理解。

其中size_t是整型,那么我们可以知道最终的结果是一个整形值,也就是j相对于0地址的偏移量。也许现在你会问,整出这么个玩意干嘛,下面看个列子:

程序运行结果:

发现没有如果把第二个值 减去最后一个值,就能得到第一个值。

在回首一下它:

1

(struct test *)((char *)__mptr - offsetof(struct test,j));

是不是可以获得结构体变量temp的首地址呀,是不是太精妙了呀

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值