continer_of 解析

本文详细解析了 Linux 内核中的 container_of 宏的工作原理及其应用。通过具体示例展示了如何利用此宏从已知结构体成员的地址计算出整个结构体的地址。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在linux内核中有这样一个带参宏:container_of

1:内核原码:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({\
        const typeof( ((type *)0)->member ) *__mptr = (ptr);\
        (type *)( (char *)__mptr - offsetof(type,member) );})

2:container_of宏的作用:

如果在知道某个结构体成员地址的情况下,可以用container_of宏计算出该结构体的地址。
例如:
struct STU{
char name[10];
int age;
int num;
};
int main(void)
{
struct STU st1,*pst;
strcpy(st1.name,"xiaoming");
st1.age = 22;
st1.num = 100;
pst = container_of(&(st1.age),struct STU,age);
printf("%d\n",st1.age);
printf("%d\n",pst->age);
return 0;
}
上面的程序会输出两个22;说明pst通过container_of计算出了结构体st1的地址。

3:参数说明

(1):结构体成员的地址
(2):结构体类型
(3):第一个参数对应的成员名字

4:宏体解析

#define offsetof(TYPE, MEMBER) (  (size_t)   &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({\
        const typeof( ((type *)0)->member ) *__mptr = (ptr);\
        (type *)( (char *)__mptr - offsetof(type,member) );})
从内核原码中可以看出:除了container_of宏之外还有一个 offsetof(TYPE,MEMBER) 的带参宏,
从参数和具体实现来看,其替换的结果是 size_t(unsigned long)类型的数据,其实是用来计算偏移量的。

下面举例说明:
例如:

定义结构:

struct STU{
char name[10];
int age;
int num;
}st1;
int offset = offsetof(struct STUE,age);

offset 的值便是age成员的地址到结构体st1的地址的偏移量,其实很好理解,offsetof在这里做了个假设:
将0地址假设为结构体的起始地址,自然某个成员的地址便成了偏移量。有了偏移量的概念,接下来讨论container_of的实现:
container_of宏可以拆分成两部分:
(1):const typeof( ((type *)0)->member ) *__mptr = (ptr);
看起来挺复杂,其实就是在定义一个变量 __mptr;其类型为:( ((type *)0)->member ) *,
说白了就和 定义一个int 型的指针一样简单(其实这一句对整个功能实现来说,意义并不大,
再接下来会讨论到。
(2):(type *)( (char *)__mptr - offsetof(type,member) );
再看这句之前必须明白:指针的加减运算和其基类型有关!
有了前面偏移量的概念,只需要再有任意一个成员地址,通过指针的减法运算,便可以计算出结构体的地址了,
最后将其强转成需要的结构体类型便完成了最终的计算。

5:改写container_of

在之前说过const typeof( ((type *)0)->member ) *__mptr = (ptr);这一句意义不大,也不知为什么内核也一直没有修改过,这里仅仅是一些个人意见。
将container_of改写成如下结构同样可以实现功能:
#define container_of(ptr, type, member)  ({(type *)( ptr - offsetof(type,member) );})
最后在贴出一个改写后的实例:
#include
#include
#define container_of(ptr,ty_pe,member) ((ty_pe *){((char *)ptr-((int) &(((ty_pe *)0)->member)))})
struct STU{
 char name[10];
 int age;
 int num;
};
int main(void)
{
 struct STU st1,*pst;
 strcpy(st1.name,"quan");
 st1.age = 22;
 st1.num = 100;

 pst = container_of(&(st1.age),struct STU,age);
 printf("%d\n",st1.age);
 printf("%d\n",pst->age);

return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值