目录
作用
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。