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

文章目录

    • `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

你可能感兴趣的:(嵌入式,rt_thread,宏定义)