从结构体成员指针反推结构体地址:rt_container_of 宏解析

ops/2025/2/9 13:08:10/

文章目录

    • `rt_container_of` 宏概述
      • 步骤1:计算成员偏移量
      • 步骤2:将成员指针转换为字节指针
      • 步骤3:计算结构体的地址
      • 步骤4:返回结构体指针
    • 代码示例
      • 宏的内部实现解析

rt_container_of 宏概述

rt_container_of 宏是一个非常实用的宏定义,它通过成员指针反向推导出整个结构体变得非常简洁和高效。这在内核编程和驱动开发中经常出现。
rt_container_of 宏的定义如下:

#define rt_container_of(ptr, type, member) \((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

该宏的目的是通过给定成员指针 ptr,计算出包含该成员的结构体的指针。现在分步骤分析宏的工作原理。

步骤1:计算成员偏移量

首先,((type *)0) 表示一个类型为 type 的空指针。这实际上是将整数 0 强制转换为指向指定类型结构体的指针。接着,&((type *)0)->member 计算出该结构体成员 member 在结构体中的偏移量。此时,&((type *)0)->member 的作用是通过一个虚拟的零地址计算成员 member 在结构体中的位置。

步骤2:将成员指针转换为字节指针

接下来,宏将 ptr 转换为 char * 类型。这一步是为了按字节来进行地址的计算,因为 char 类型的指针可以进行字节级的地址偏移。

步骤3:计算结构体的地址

然后,通过 ptr 和成员的偏移量,利用 (char *)(ptr) - offset 来计算整个结构体的起始地址。这一步将成员指针向回移动 member 在结构体中的偏移量,从而得到了包含该成员的整个结构体的地址。

步骤4:返回结构体指针

最后,宏将计算出来的地址转换为 type * 类型,得到结构体的指针。

代码示例

假设我们有如下的结构体定义:

// 定义一个结构体
struct example {int x;int y;
};

接下来,我们初始化结构体实例并取得成员 y 的指针:

struct example obj;
obj.x = 100;
obj.y = 200;// 假设我们有一个指向成员 y 的指针
int *p_y = &obj.y;

此时,我们有一个指向成员 y 的指针 p_y,但我们希望根据该指针反推出整个结构体的指针。此时就可以使用 rt_container_of 宏来实现这一功能:

struct example *p_obj;
p_obj = rt_container_of(p_y, struct example, y);

宏的内部实现解析

  1. ((type *)0)0 强制转换为指向 struct example 类型的指针。
  2. &((type *)0)->y 计算出成员 ystruct example 中的偏移量。
  3. (char *)(p_y) 将成员指针 p_y 转换为 char * 类型,便于按字节计算地址。
  4. (char *)(p_y) - offset 通过减去偏移量,回退到结构体的起始地址。
  5. 最后,将计算出的地址转换为 struct example * 类型,得到整个结构体的指针。

至此,我们成功地从 p_y 反推出了结构体 obj 的指针 p_obj


http://www.ppmy.cn/ops/156975.html

相关文章

web3D交互展示是什么?应用场景有哪些?

Web3D交互展示是利用Web3D技术,在网页上实现3D产品的全方位交互展示。用户可自由旋转、缩放及移动产品视角,从而深入了解产品的每一处细节与尺寸信息。以下是关于Web3D交互展示的详细解释: 一、定义与原理 定义:Web3D交互展示是…

PMP–一、二、三模–分类–13.干系人管理

文章目录 技巧十三、干系人管理 一模13.干系人管理--引言--项目进入其生命周期的不同阶段;当前干系人不再与项目工作有关,或者在项目的干系人社区中出现了新的干系人成员;组织内部的干系人社区发生重大变化,出现以上三点情况时要重…

【react】react面试题

react面试题 1.对 React 的理解、特性 2.react18有哪些更新 3.JSX是什么 4.解释为什么浏览器不能读取jsx 6.ReactNative中,如何解决8081端口被占用而提示无法访问的问题? 7. React 生命周期 8.react事件机制 9.react 组件传值 10.React改…

zzcms接口index.php id参数存在SQL注入漏洞

zzcms接口index.php id参数存在SQL注入漏洞 漏洞描述 ZZCMS 2023中发现了一个严重漏洞。该漏洞影响了文件/index.php中的某些未知功能,操纵参数id会导致SQL注入,攻击可能是远程发起的,该漏洞已被公开披露并可被利用。攻击者可通过sql盲注等手段,获取数据库信息。 威胁等级:…

数据结构--八大排序算法

1. 直接插入排序 当插入第 i(i>1) 个元素时,前面的 array[0],array[1],…,array[i-1] 已经排好序,此用 array[i] 的排序码与 array[i-1],array[i-2],… 的排序码顺序进行比较,找到插入位置即将 array[i] 插入,原来位置上的元素…

Rust 的内存管理机制

Rust 的内存管理机制是其最核心的创新之一,它通过 所有权系统(Ownership)、借用检查器(Borrow Checker) 和 生命周期(Lifetimes) 在编译期静态保障内存安全,无需垃圾回收(GC)且避免手动管理内存的错误。下面通过代码示例详细解析其机制和安全性原理: 1. 所有权系统(…

uniapp 使用 tree.js 解决模型加载不出来的问题

网上有很多uniapp使用tree.js的教程,但是我在使用测试中,发现tree.js的官方3d模型中有很多加载不出来,但是也没有报错,全网搜也没搜到方法,最后发现是缩放的问题,这里将代码贴出来,关键的方法是…

MySQL基于binlog和gtid主从搭建方案

MySQL基于binlog和gtid主从搭建方案 一.主库配置 1.1 确认 binlog 是否开启 SHOW VARIABLES LIKE %log_bin%; 1.2 创建日志目录并设置权限 mkdir -p /opt/mysql/log_bin chown -R mysql:mysql /usr/local/mysql chmod -R 755 /usr/local/mysql 1.3 修改 my.cnf 配置文件 …