container_of(ptr, type, member)宏的作用
该宏的作用是通过结构体成员的地址和结构体类型推导出结构体的地址,type是指结构体的类型,member是成员在结构体中的名字,ptr是该成员在type结构体中的地址。
container_of(ptr, type, member)宏解析
在 linux 源码的 toolsincludelinuxkernel.h文件下,container_of()的定义如下:
#ifndefcontainer_of
/**
*container_of-castamemberofastructureouttothecontainingstructure
*@ptr:thepointertothemember.
*@type:thetypeofthecontainerstructthisisembeddedin.
*@member:thenameofthememberwithinthestruct.
*
*/
#definecontainer_of(ptr,type,member)({
consttypeof(((type*)0)->member)*__mptr=(ptr);
(type*)((char*)__mptr-offsetof(type,member));})
#endif
在 container_of() 宏的定义中的 offsetof(TYPE, MEMBER) 和 typeof() 初学者可能会对其很陌生,所以我们要先从理解 offsetof(TYPE, MEMBER) 和 typeof() 的作用开始。
offsetof(TYPE, MEMBER)
本质也是个宏定义,在 linux 源码的 toolsincludelinuxkernel.h 文件下定义如下:
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
offsetof 宏中的 TYPE 是指结构体的类型,MEMBER 是指结构体中的某个成员,作用是求出该成员的在该结构体中的偏移量。该宏首先将 0 (地址0)转化为 TYPE * 的结构体指针,表示地址为 0 的结构体指针,然后通过取地址符 &((TYPE *)0)->MEMBER) 取出该结构体指针中 MEMBER 成员的地址,最后再将地址值强转为 size_t 类型(内核中为 unsigned long 类型)即表示 MEMBER 成员在结构体中的偏移量。要理解该过程需要了解对结构体的内存分布,如图,结构体的内存分配是连续的,当结构体的地址为0时,成员的地址即为该成员的偏移量。

实例:
#include
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
typedefstruct_offset
{
charmember_0;
intmember_1;
charmember_2;
}offset;
intmain()
{
printf("%d
",offsetof(offset,member_0));
printf("%d
",offsetof(offset,member_1));
printf("%d
",offsetof(offset,member_2));
return0;
}
输出:

typeof()
typeof() 是 GNU C 中的一个关键字,和 sizeof() 一样都是 C 语言中的关键字而不是函数。作用是返回传入数据的类型。实例:
#include
intmain()
{
inta=3;
typeof(a)b=a;/*求出a变量的类型,并创建一个b变量*/
printf("a=%db=%d",a,b);
return0;
}
输出:

container_of(ptr, type, member)
了解了 offsetof() 宏和 typeof 关键字之后就比较好理解 container_of 宏的作用了。
consttypeof(((type*)0)->member)*__mptr=(ptr)
该代码的作用实际上是将 0 转化为 type * 结构体类型,再取出结构体中的MEMBER成员 (type *)0)->member, 再通过 typeof 关键字获取 MEMBER 成员的类型,并定义一个 MEMBER 成员类型的指针 const typeof(((type *)0)->member) * __mptr,将传入的 ptr 指针赋值给 __mptr__mptr = (ptr)。
(type*)((char*)__mptr-offsetof(type,member));
该代码是将获取的 MEMBER 成员地址强转为 char *(强转的目的是考虑指针的加减的实质是指针在内存的偏移,偏移量为指针类型所占字节的个数),减去 MEMBER 成员在 type 结构体中的偏移量,强转为 type * 后得到结构体的地址。实例:
#include
#ifndefoffsetof
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
#ifndefcontainer_of
#definecontainer_of(ptr,type,member)({
consttypeof(((type*)0)->member)*__mptr=(ptr);
(type*)((char*)__mptr-offsetof(type,member));})
#endif
typedefstruct_container
{
charmember_0;
intmember_1;
charmember_2;
}container;
intmain(void)
{
container*a=NULL;
containerb={'a',2,'b'};
/*member_1在实例结构体中的地址结构体类型成员名*/
a=container_of(&b.member_1,container,member_1);
printf("a->member_0=%c
",a->member_0);
printf("a->member_1=%d
",a->member_1);
printf("a->member_2=%c
",a->member_2);
return0;
}
输出:

-
Linux
+关注
关注
88文章
11628浏览量
217989 -
源码
+关注
关注
8文章
682浏览量
31094 -
结构体
+关注
关注
1文章
131浏览量
11300
原文标题:container_of()宏,太妙了~
文章出处:【微信号:嵌入式情报局,微信公众号:嵌入式情报局】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
详细聊聊container_of这个宏定义
揭开linux内核中container_of的神秘面纱
Labview Active Container引用AUTODESK控件后异常?
鸿蒙应用开发-container动漫效果体验
Linux内核中的C语言语法扩展
请教一下大神内核源码中的containerof该怎样去实现呢
RT-Thread中侵入式链表的应用有哪些呢
Linux内核基础-container_of
Accelerated Container Image基于块设备的容器镜像加速服务
Missing Container Metrics容器指标收集工具
Linux内核中的宏/container_of分析

container_of()宏,太妙了~
评论