Linux / offsetof 和 container_of

@time        2019-07-10
@author      Ruo_Xiao
@revision    linux  2.6.11

1、 offsetof 

(1)原型

/*
 * @member    TYPE    : 结构体原型。
 *            MEMBER  : 结构体成员。  
 */
#define offsetof(TYPE , MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

 

(2)文件路径:/ include / linux / stddef.h

(3)作用

返回指定类型(TYPE)的成员(MEMBER)在该结构体内的偏移量。

(4)解析

         A、(TYPE *) 0

                  将以地址 0 为开始的,大小为 sizeof(TYPE) 的内存块按照 TYPE 进行看待。注意,这里只是看待,并没有进行读                取!这就保证了代码执行到这里并不会报错!

         B、((TYPE *) 0) -> MEMBER

                  看看 MEMBER 成员,还是没有读取。

         C、&(((TYPE *) 0) -> MEMBER)

                 看看 MEMBER 成员地址,还是没有读取。因为结构体的首地址为0,所以得到的 MEMBER 的首地址就是该成员相对            于结构体首地址的偏移量。

         D、(size_t)&(((TYPE *)0) -> MEMBER)

                 将该地址转为 size_t 类型。

          在32位系统中,size_t 的原型是 unsigned int

          在64位系统中,size_t 的原型是 unsigned long

(5)栗子

#include <iostream>

#define offsetof_t(TYPE , MEMBER) ((size_t)&(((TYPE *)0)->MEMBER))

struct stest
{
    char    c;
    int     i;
    float   f;
    double  d;
};

int main()
{
    int pos_c = offsetof_t(stest , c);
    int pos_i = offsetof_t(stest , i);
    int pos_f = offsetof_t(stest , f);
    int pos_d = offsetof_t(stest , d);

    std::cout << "stest::c 的偏移量:" << pos_c << std::endl;
    std::cout << "stest::i 的偏移量:" << pos_i << std::endl;
    std::cout << "stest::f 的偏移量:" << pos_f << std::endl;
    std::cout << "stest::d 的偏移量:" << pos_d << std::endl;
    return 0;
}

结果:

stest::c 的偏移量:0
stest::i 的偏移量:4
stest::f 的偏移量:8
stest::d 的偏移量:16

 

2、container_of

(1)原型

/*
 * @member    ptr    结构体成员的地址。
 *            type   结构体原型。
 *            member 结构体成员。
 */
#define container_of(ptr, type, member) ({			\
        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
        (type *)( (char *)__mptr - offsetof(type,member) );})

(2)文件路径:/ include / linux / kernel.h

(3)作用:通过结构体成员地址反推该结构体的地址。

(4)解析

         A、typeof(  ( (type*)0 ) -> member ) )

                  获得 member 成员的数据类型。

         B、const typeof(  ( (type*)0 ) -> member ) )  *_mptr = (ptr)

                  定义常量指针 _mptr,指向 ptr 指向的内容,该指针变量指向的内容是不可变的。

         C、(char *)_mptr - offsetof(type , member)

                  前者将 _mptr 变为 字符指针,后者返回 member 在 type 的偏移量,二者相减就是 type 的首地址了。

           最后在通过  (type *) 转为 type 型地址就可以了。

(5)栗子

#include <iostream>

struct stest
{
    char    c;
    int     i;
    float   f;
    double  d;
};

#define offsetof_t(TYPE , MEMBER) ((size_t)&(((TYPE *)0)->MEMBER))

#define container_of_test(ptr , type , member) ({\
    const typeof(((type *)0)->member) *_mptr = ptr;\
    (type *)((char *)ptr - offsetof_t(type , member));})

int main()
{
    stest test1;
    stest *p;
    p = container_of_test(&test1.i , stest , i);
    if (p == &test1)
    {
        std::cout << "二者相同。" << std::endl;
    }
    else
    {
        std::cout << "二者不同。" << std::endl;
    }
}

结果:

二者相同

 

 

(SAW:Game Over!)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值