当前位置: 首页 > news >正文

container_of 函数的分析

这个函数的目的是, 通过结构体里面的内容 找到 大结构体的 基地址。

函数的原型是: 

PTR是指针

type , member 都是具体的类型。

   12 /**11 ▎* container_of - cast a member of a structure out to the containing structure10 ▎* @ptr:    the pointer to the member.9 ▎* @type:   the type of the container struct this is embedded in.8 ▎* @member: the name of the member within the struct.7 ▎*6 ▎*/5 #define container_of(ptr, type, member) ({              \4 ▎   void *__mptr = (void *)(ptr);                   \3 ▎   BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \2 ▎   ▎   ▎    !__same_type(*(ptr), void),            \1 ▎   ▎   ▎    "pointer type mismatch in container_of()");    \856 ▎   ((type *)(__mptr - offsetof(type, member))); })12 /**

--------------------------------------------------------------------------------------------------------------------------

先来看一个 我自己的 追踪,

 接下来看一下  offsetof() 函数

结果是个这个。

再来追踪  __builtin_offsetof() 函数就追踪不到了,这是一个  GCC的函数。

从网上找找这个函数的实现。

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

接下来 解释 一下 这个函数。还是 又不少的东西的。

首先是 这个 : (TYPE *)0)->MEMBER

它的意思是 , 在 TYPE 这个结构体中, 找到 MEMBER成员, 但是 编译器 首先会找到 MEMBER的偏移地址, 并不会 对 0 地址的内存有什么操作 , 先。

然后是:   &((TYPE *)0)->MEMBER)   , 这意味着  我不是已经找到了MEMBER的的位置了吗, 现在 对这个位置 取地址,你知道,基地址是0 , 所以 MEMBER的地址,就是一个相对地址, 这样我实际上找到的是 TYPE 与MEMBER的差值。但是这个地址值,是有类型的,类型就是 MEMBER* 。

然后就是:   ((size_t) &((TYPE *)0)->MEMBER)    我把它强制转换成了一个 int 类型, 这就是一个数字了。

然后就是: __mptr - offsetof(type, member)))   这实际上就是 __mptr 减去一个 int 型的数字,

void *__mptr = (void *)(ptr)  这句说明, __mptr 是一个 void* 的指针。 那么   这句 __mptr - offsetof(type, member)))  就变成了  指针 加减 一个 整数了。

如果是在堆中的话,我们知道,堆是从下往上增长的。

那么  这个  ((size_t) &((TYPE *)0)->MEMBER)  将是一个正数。

那么  __mptr - offsetof(type, member)))  这个  意味着指针的位置 , 在从上往下 减, 也就是从一个小结构体, 找到了一个大结构体的 基地址。

然后就是:   ((type *)(__mptr - offsetof(type, member)));   这个函数的 type* 就是 在将 计算出的 大结构体的 指针 (这是一个数字), 转换成 大结构体指针类型,用于寻找 在这个大结构体 中的其他成员。

------------------------------------------------------------------------------------------------------------------------

来看看我自己的测试。

我是在 4412  arm 的裸机程序中做的测试。

 71 #define size_t unsigned int72 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)7374 struct human_mod{7576     int     head;77     char    eye;78     float   foot;79 };808182 int main(void)83 {84         size_t ret;85         ret = offsetof(struct human_mod , foot);86         int i = 0;87         led_init ();88         while(1)89         {9091                 led_on(i%2);92                 led_off(((i-1)+2)%2);93                 i++;94                 delay_ms(500);9596         }97     return 0;98 }

这是 汇编的结果:


int main(void)
{
40008198:       e92d4800        push    {fp, lr}
4000819c:       e28db004        add     fp, sp, #4
400081a0:       e24dd008        sub     sp, sp, #8
/home/topeet/topeet_wang_4412_for_yikoulinux/yikoulinux_code/led_c/led.c:85size_t ret;ret = offsetof(struct human_mod , foot);
400081a4:       e3a03008        mov     r3, #8
400081a8:       e50b300c        str     r3, [fp, #-12]
/home/topeet/topeet_wang_4412_for_yikoulinux/yikoulinux_code/led_c/led.c:86int i = 0;
400081ac:       e3a03000        mov     r3, #0
400081b0:       e50b3008        str     r3, [fp, #-8]
/home/topeet/topeet_wang_4412_for_yikoulinux/yikoulinux_code/led_c/led.c:87led_init ();
400081b4:       ebffff95        bl      40008010 <led_init>
/home/topeet/topeet_wang_4412_for_yikoulinux/yikoulinux_code/led_c/led.c:91while(1){

也就是说 ,汇编的是 已经是结果了,而不是 过程。

这里 直接 把 8 这个数字算出来了。 看来汇编代码 还不底层,更底层的应该是 编译器源码了。

400081a4:       e3a03008        mov     r3, #8


http://www.mrgr.cn/news/39323.html

相关文章:

  • yolov8/9/10模型在安全帽、安全衣检测中的应用【代码+数据集+python环境+GUI系统】
  • UnityComputeShader Challenge1
  • 算法题题解:分隔链表
  • Java方法+数组介绍
  • WIFI密码默认显示
  • 猫咪掉毛太严重,有什么好办法?不踩雷宠物空气净化器选购、测评指南
  • fastadmin搜索刷新列表,怎么限制用户频繁点击?
  • 电脑使用adb工具连接手机,全文完整教程
  • pdf页面尺寸裁减
  • One2many(一对多)关联场景中,如何从模型(一)关联到模型(多)的某个字段
  • 【JavaEE初阶】文件IO(下)
  • 算法打卡:第十一章 图论part10
  • CSS给一行按钮统一设置间隔
  • C# 调用虚拟打印,尝试隐藏进度窗体
  • 低代码平台中的宿主概念解析与字典、角色、岗位及权限管理
  • 推荐4款2024年热门的PDF转ppt工具
  • CSS 的user-select属性,控制用户是否能够选中文本内容
  • 基于springboot+小程序的自习室选座与门禁管理系统(自习室1)(源码+sql脚本+视频导入教程+文档)
  • [算法日常] 分层图最短路
  • 心觉:如何重塑高效学习的潜意识(5)终结篇