Linux第一宏:container_of

这段代码展示了 Linux 内核编程中最经典的两个宏:offsetofcontainer_of。它们是 C 语言中实现"逆向寻找结构体入口"的核心工具。

下面我为你逐行拆解这两个宏的工作原理。


1. offsetof 宏:计算成员偏移量

c 复制代码
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  • 目的 :计算结构体成员 MEMBER 距离结构体 TYPE 起始地址的字节数。
  • 拆解
    1. (TYPE *)0:将地址 0 强制转换为指向 TYPE 结构体的指针。这并不会导致崩溃,因为我们只是在进行地址运算,并没有真正去读取(解引用)这个地址里的内容。
    2. ((TYPE *)0)->MEMBER:假设结构体从 0 开始,我们要访问其中的 MEMBER
    3. &(...):获取这个成员的地址。
    4. 由于起始点是 0,那么成员的地址值(例如 8)刚好就是它相对于起始点的偏移量
    5. (size_t):最后强制转换为无符号整型。

2. container_of 宏:根据成员指针找结构体首地址

这是内核开发的"黑科技",它能让你在只知道某个成员指针的情况下,反向推导出整个结构体的首地址。

c 复制代码
#define container_of(ptr, type, member) ({ \
    const typeof( ((type *)0)->member ) *__mptr = (ptr); \
    (type *)( (char *)__mptr - offsetof(type,member) );})
  • 参数说明

    • ptr:指向结构体内部成员的指针。
    • type:容器结构体的类型。
    • member:成员在结构体中的变量名。
  • 拆解

    1. 第一行(类型安全检查)
      • typeof( ((type *)0)->member ):通过 typeof 获取成员的实际类型。
      • 它定义了一个临时指针 __mptr 指向 ptr。如果 ptr 的类型和结构体定义的成员类型不匹配,编译器会报错,保证了程序的健壮性。
    2. 第二行(核心计算)
      • (char *)__mptr:将成员指针强转为 char *,因为 char 的大小是 1 字节,指针加减运算是以字节为单位进行的。
      • - offsetof(type, member):用成员的实际地址 减去成员在结构体中的偏移量
      • (type *):最后将计算得到的地址强转为结构体类型。

3. 图解与例子

假设我们有如下结构体:

c 复制代码
struct Person {
    int age;      // 偏移量 0
    char gender;  // 偏移量 4
    int id;       // 偏移量 8
};

struct Person p1;
int *id_ptr = &p1.id; // 我们手里只有指向 id 的指针

如果我们想通过 id_ptr 找到 p1 的起始位置:

  1. offsetof(struct Person, id) 的值是 8
  2. container_of(id_ptr, struct Person, id) 的逻辑是:
    • 获取 id_ptr 的内存地址(比如 0x1008)。
    • 计算 0x1008 - 8 = 0x1000
    • 0x1000 就是结构体 p1 的起始地址。

4. 为什么要这么做?

这种设计模式被称为**"侵入式链表(Intrusive Link List)"**。

在传统的 Java 或 C++ 集合类中,是容器包裹数据。但在 Linux 内核中,为了追求极致效率,通常是将"链表节点"嵌入到具体的业务结构体中。当内核遍历链表得到一个节点指针时,它必须通过 container_of 找回包含这个节点的业务结构体,从而访问其数据。

总结:

  • offsetof:我在结构体的什么位置?
  • container_of:我是谁的成员?(找到"父亲"是谁)

linux内核源码

相关推荐
知产xiao_xin11 小时前
知识产权入门 —— 相关权(邻接权)
经验分享·笔记·知识产权
虎王物联11 小时前
STM32 HAL库串口DMA空闲中断:高效接收不定长Modbus数据帧
stm32·单片机·嵌入式硬件·dma·modbus
自小吃多11 小时前
DXF文件导入与PCB板框定义笔记
笔记·嵌入式硬件
是隼人12 小时前
buuctf-pwn xdctf2015_pwn200题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
jike_202613 小时前
iPhone采访录音同时拍现场照片的APP:图片音频同步记录实测
笔记·智能手机·音视频·语音识别
大衛說13 小时前
《Python 从入门到精通》系列总览与学习路线
开发语言·python·学习
单片机仿真设计14 小时前
【proteus仿真】基于 STC89C52 单片机家用智能台灯设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
2601_9507906814 小时前
深圳国产单片机厂商怎么选?技术能力与服务能力检查表
单片机·嵌入式硬件·国产mcu·芯片厂商·深圳单片机·单片机选型
吃好睡好便好14 小时前
查找函数的使用
学习·算法·matlab·生活·查找函数
学运维的Kysan14 小时前
暑假运维学习打卡第二十九天8.29
学习