0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

container_of()宏,太妙了~

嵌入式情报局 来源:嵌入式情报局 2023-09-10 10:59 次阅读

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时,成员的地址即为该成员的偏移量。

758a6386-4f09-11ee-a25d-92fbcf53809c.png

实例:

#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;

}

输出:

75a02496-4f09-11ee-a25d-92fbcf53809c.png

offsetof实例结果输出

typeof()

typeof()GNU C 中的一个关键字,和 sizeof() 一样都是 C 语言中的关键字而不是函数。作用是返回传入数据的类型。实例:

#include

intmain()
{
inta=3;
typeof(a)b=a;/*求出a变量的类型,并创建一个b变量*/


printf("a=%db=%d",a,b);

return0;
}

输出:

75b50758-4f09-11ee-a25d-92fbcf53809c.png

img

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;
}

输出:

75c25a34-4f09-11ee-a25d-92fbcf53809c.png


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11031

    浏览量

    207275
  • 源码
    +关注

    关注

    8

    文章

    601

    浏览量

    28740
  • 结构体
    +关注

    关注

    1

    文章

    126

    浏览量

    10774

原文标题:container_of()宏,太妙了~

文章出处:【微信号:嵌入式情报局,微信公众号:嵌入式情报局】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux内核中container_of原理详解

    Linux内核中经常可见container_of的身影,它在实际驱动的编写中也是广泛应用。
    发表于 07-14 15:19 212次阅读
    Linux内核中<b class='flag-5'>container_of</b>原理详解

    详细聊聊container_of这个宏定义

    大家周末好,我是bug菌~ 今天主要是跟大家详细聊聊container_of这个宏定义,非常经典的宏,只是一直没有抽时间细细品味,今天就跟大家一起来看看有何神奇之处。
    的头像 发表于 11-13 09:45 436次阅读

    揭开linux内核中container_of的神秘面纱

    在linux 内核中有一个大名鼎鼎的container_of(),这个是用来干嘛的呢?我们先来看看它在内核中是怎样定义的。呵呵,乍一看不知道是什么东东。我们先来分析一下container_
    发表于 11-11 10:02

    offsetofcontainer_of详解

    offsetofcontainer_of详解 1.offsetofcontainer_of
    发表于 10-13 16:35

    Labview Active Container引用AUTODESK控件后异常?

    使用Labview active container引用后,单个VI运行是正常的,单将单个VI引入后,出现异常,这种问题需要怎样解决,有相关经验的人没。
    发表于 05-19 18:31

    鸿蒙应用开发-container动漫效果体验

    `container案例练习。 点击按钮触发事件,两个方块颜色发生渐变。 Hml代码如下:<!-- xxx.hml --><div class
    发表于 04-09 16:37

    Linux内核中的C语言语法扩展

    收集一些感觉比较好的博客链接,方便以后再看Linux 内核中的 C 语言语法扩展Linux 内核驱动中的指定初始化宏构造利器:语句表达式Linux 内核第一container_of零长
    发表于 12-15 06:04

    请教一下大神内核源码中的containerof该怎样去实现呢

    内核中源码是这样的#define container_of(ptr, type, member) ({\ const typeof( ((type *)0)->member ) *__mptr
    发表于 05-07 11:00

    RT-Thread中侵入式链表的应用有哪些呢

    rt_container_of(ptr, type, member)((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))具体的解析参见:list_entry/
    发表于 12-05 13:59

    Linux内核基础-container_of

    TYPE是某struct的类型,0是一个假想TYPE类型struct,MEMBER是该struct中的一个成员。 由于该struct的基地址为0, MEMBER的地址就是该成员相对与struct头地址的偏移量。
    发表于 05-14 14:26 798次阅读

    Accelerated Container Image基于块设备的容器镜像加速服务

    ./oschina_soft/accelerated-container-image.zip
    发表于 05-10 11:15 0次下载
    Accelerated <b class='flag-5'>Container</b> Image基于块设备的容器镜像加速服务

    container-diff容器镜像分析对比工具

    ./oschina_soft/container-diff.zip
    发表于 05-11 10:35 0次下载
    <b class='flag-5'>container</b>-diff容器镜像分析对比工具

    Ansible Container容器自动化构建部署工具

    ./oschina_soft/ansible-container.zip
    发表于 05-11 10:15 1次下载
    Ansible <b class='flag-5'>Container</b>容器自动化构建部署工具

    Missing Container Metrics容器指标收集工具

    ./oschina_soft/missing-container-metrics.zip
    发表于 05-12 14:24 1次下载
    Missing <b class='flag-5'>Container</b> Metrics容器指标收集工具

    Linux内核中的宏/container_of分析

    今天在看平台设备实现的时候,看到to_xxx开头的“函数”。包括在内核中也有很多此类的“函数”,其实他们都是container_of的宏。因为内核是链表和结构体的世界,因此内核中有大量需求要 根据结构体成员获取结构体地址 ,或者根据结构体类型和结构体成员类型获取成员在结构体的偏移。
    发表于 06-23 14:26 256次阅读
    Linux内核中的宏/<b class='flag-5'>container_of</b>分析