rt_container_of 作用和实现过程超级详解介绍

目录

作用

ptr 获取

偏移size获取


函数作用

我们先看段代码,了解rt_container_of有什么用处:

#include "stdio.h"
#define rt_container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

struct STabcde
{
    uint32_t a;
    uint32_t b;
    uint32_t c;
    uint32_t d;
};
struct STest
{
    uint32_t lentotal;
    uint32_t flag;
    uint32_t in;
    uint32_t out;
    uint8_t buf[10];
    struct STabcde STdata;
};
void funtion_t1(uint8_t * inputbuf)
{
    struct STest *S;
    int i;
    S = rt_container_of(inputbuf,struct STest,buf[0]);
    printf("struct STest S address[0x%08x]\r\n",&S);
    printf("struct STest S1.lentotal = %d\r\n",S->lentotal);
    for(i = 0;i < S->lentotal;i++)
    {
        inputbuf[i] = i;        
    }
}
void funtion_t2(struct STabcde * inputST)
{
    struct STest *S;
    int i;
    S = rt_container_of(inputST,struct STest,STdata);
    printf("struct STest S address[0x%08x]\r\n",&S);
    for(i = 0;i < S->lentotal;i++)
    {
        printf("S->buf[%d] = %d\r\n",i,S->buf[i]);     
    }
}
int main()
{
    struct STest S1;
    printf("struct STest S1 address[0x%08x]\r\n",&S1);
    S1.lentotal = 10;
    funtion_t1(S1.buf);
    funtion_t2(&S1.STdata);
    return 0;
}

最后运行的结果是:

通过上面的代码我们会发现,funtion函数中只传入struct STest S1里面成员变量地址,函数里面通过 rt_container_of获取到的struct STest *S的地址实际上就是主函数中声明的struct STest S1的地址,struct STest *S = &S1

通过上面的代码就能知道rt_container_of 的作用,即:查找当前结构体成员所在的结构体的首地址

实现方法

问题来了,rt_container_of怎么做到的?

答案是:通过当前成员的地址减去结构体首地址成员地址的偏移。

ptr - size可以获得父结构体的起始地址Addre1

ptr 获取

当前成员的地址ptr很好获取 ,就是函数传入的地址。rt_container_of中强制声明为char *类型的地址,强制声明的意义就是让编译器知道ptr应该按字节地址类型来计算。

#define rt_container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

回到rt_container_of 函数中:(char *)(ptr)就是做了对应操作,获取了当前成员的地址。

偏移size获取

最关键的结构体首地址成员地址的偏移,则通过了一些小技巧来获取。

如上图可知:size = member_Address -  Address1

假设有个父结构体的首地址在0x100(Address1 = 0x100),那size = member_Address -  0x100

关键来了,如果假设有个父结构体在、的首地址在0(Address1 = 0)呢,

size = member_Address -  0

父类结构体首地址成员地址的偏移就是:父类结构体其首地址为0时的该成员的地址。

回到rt_container_of 函数中,

#define rt_container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

(type *)0意义是强制声明在0地址有个type类型,&((type *)0)->member)就是指向结构体的成员member,通过取址符号&获取其地址,因为当前结构体的首地址是0,所以该结构体的成员的地址就是Size。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值