contain_of的原理与实现

文章详细解释了contain_of宏的用途,即从结构体变量的一个成员地址反推出整个结构体的地址。通过相对地址的概念,说明了如何根据成员变量的地址和其在结构体内的偏移来计算结构体首地址。文章提供了contain_of宏的实现代码,并通过示例验证了其正确性。
摘要由CSDN通过智能技术生成

contain_of的作用是:已知一个结构体变量的某个成员的地址,怎么获取这个结构体变量的地址。

比如存在如下结构体:

struct Test
{
    int a;
    int b;
    int c;
};

定义一个对应的结构体变量:

struct Test num;

已知num.b的地址,请问怎么拿到num的地址?

如果是人为计算,那么我们知道num的地址其实和结构体成员变量a的地址是同一个。a刚好在b的前面,又是int型,所以a的地址=b的地址-4。然后就可以得到a的地址,也就拿到了num的地址。

其实这里的算法,应用的就是相对地址的概念。即结构体里面的各个成员变量的相对地址是确定的。只要知道了一个成员变量的地址,那么我们就可以根据偏移地址得到其他成员变量的地址。

contain_of的实现原理就是:我们以0地址作为结构体变量的首地址。那么该结构体里面的成员变量的地址就自然变成了相对地址。拿到了成员变量相对地址,再结合结构体变量的地址,就能计算出结构体变量的首地址。举个例子:

struct Test
{
    int a;
    int b;
    int c;
};

struct Test *p=NULL;             //定义一个指针
p = (struct Test *)0;            //这个指针指向0地址
//那么p->a的地址就是0    计算公式:&(p->a) - 0    
//p->a的地址的值就是struct Test结构体里面成员变量a的偏移地址  
  
//那么p->b的地址就是4    计算公式:&(p->b) - 0    
//p->b的地址的值就是struct Test结构体里面成员变量b的偏移地址

//那么p->c的地址就是8    计算公式:&(p->c) - 0    
//p->c的地址的值就是struct Test结构体里面成员变量c的偏移地址

struct Test num;    //定义一个struct Test结构体变量
//假设现在我们已知num.b的地址是0x00000064
//请问num的地址是多少?
//num的地址=num.b的地址-成员变量b的偏移地址

通过上面的介绍,我们了解了contain_of的原理,接下来我们自己来实现contain_of:

#define contain_of_lqd(ptr, type, member) \
    ((type *)((size_t)ptr - (size_t)&(((type *)0)->member)))
//ptr:结构体变量的成员变量的指针
//type:结构体类型
//member:ptr对应结构体的成员变量名字

//(size_t)ptr:将指针转换成整型
//(type *)0:将0地址转换成结构体变量的地址
//&(((type *)0)->member):取0地址对应的结构体成员变量member的地址
//(size_t)&(((type *)0)->member):将地址转换成整型

完整测试代码:

#include <stdio.h>

#define container_of_lqd(ptr, type, member) \
    ((type *)((size_t)ptr - (size_t)&(((type *)0)->member)))

struct Test
{
    int a;
    int b;
    int c;
};

int main()
{
    struct Test num;
    struct Test *p=NULL;
    
    printf("num    addr=%p\n", &num);
    printf("a    addr=%p\n", &num.a);
    printf("b    addr=%p\n", &num.b);
    printf("c    addr=%p\n", &num.c);
    
    p = (struct Test *)container_of_lqd(&num.b, struct Test, b);
    printf("p    addr=%p\n", p);

    return 0;
}

我的测试结果:

lqd@ubuntu:~/lqd/c/container_of$ ./a.out 
num    addr=0x7ffd91c78cf0
a    addr=0x7ffd91c78cf0
b    addr=0x7ffd91c78cf4
c    addr=0x7ffd91c78cf8
p    addr=0x7ffd91c78cf0
lqd@ubuntu:~/lqd/c/container_of$ 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

monkey_llll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值