container_of分析

本文深入解析了container_of宏的功能与实现原理,详细解释了如何通过对象成员指针获取对象指针的过程,包括ptr、type、member的含义及offsetof宏的作用,展示了C语言中指针的强大特性。

container_of是一个伟大的宏,其实现非常巧妙,值得学习。功能:根据对象的一个成员指针获取该对象的指针

#define container_of(ptr, type, member)({ /
const typeof(((type*)0)->member)*__mptr=(ptr); /
(type *)((char*)__mptr-offsetof(type,member));})

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

1.ptr为物理地址,其类型和member类型一致,最终使用typeof(((type*)0)->member)由编译器自动返回member的类型
2.type为包含member成员的结构体
3.offsetof(type,member)为member成员在type结构体中的偏移值,大小范围0~sizeof(type)字节
(因为以0地址为type类型数据结构的起始地址)
4.ptr- offsetof()就等于包含该ptr的type结构体父变量的物理起始地址,强制转换为(type*).

值得一提的是,offsetof宏的实现非常巧妙,它把0地址转化为TYPE结构的指针,然后获取该结构中MEMBER成员的指针,并将其强制类型 转换为size_t类型。于是,由于结构从0地址开始定义,因此,cast后的MEMBER成员地址,实际上就是它在结构中的偏移量。这也显示出了C语言中指针的强大。因为,在某个体系结构下实现的libc,结构中各个成员的偏移总是可以预见的。offsetof的定义在stddef.h中。

container_of宏的作用是从包含在某个结构体中的结构成员获取结构体本身的指针,也就是通过结构体变量中的某个成员的首地址获取结构体的首地址。其实现原理如下: ### 原型定义 ```c #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ``` ### 原理分析 1. **offsetof宏的作用**:`offsetof(TYPE, MEMBER)` 宏用于计算结构体 `TYPE` 中成员 `MEMBER` 相对于结构体起始地址的偏移量。它的实现方式是将 `0` 强制转换为 `TYPE *` 类型的指针,这意味着将地址 `0` 视为结构体的起始地址。然后通过 `->` 操作符访问成员 `MEMBER`,并取其地址。由于结构体起始地址为 `0`,所以该成员的地址值就等于其相对于结构体起始位置的偏移量。最后将其转换为 `size_t` 类型返回 [^1][^4]。 2. **container_of宏的实现**: - 首先,`const typeof(((type *)0)->member) * __mptr = (ptr);` 这一行代码定义了一个临时指针 `__mptr`,其类型与结构体 `type` 中成员 `member` 的类型相同,并将传入的成员指针 `ptr` 赋值给它。这一步主要用于类型检查,确保传入的指针类型与结构体成员类型一致 [^1][^4]。 - 接着,`(type *)((char *)__mptr - offsetof(type, member));` 这一行是核心计算部分。先将 `__mptr` 强制转换为 `char *` 类型,这是因为 `char` 类型的指针在进行指针运算时,每次移动的步长为 `1` 字节。然后用成员指针 `__mptr` 减去成员相对于结构体起始位置的偏移量,得到结构体的起始地址。最后将结果强制转换为 `type *` 类型,即结构体指针类型 [^1][^4]。 ### 简单示例 ```c #include <stdio.h> #include <stddef.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) // 定义一个结构体 struct example { int a; char b; double c; }; int main() { struct example var; // 获取成员 c 的地址 double *c_ptr = &var.c; // 通过 container_of 宏获取结构体的地址 struct example *ptr = container_of(c_ptr, struct example, c); // 验证获取的结构体地址是否正确 if (ptr == &var) { printf("Successfully retrieved the address of the structure!\n"); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值