container_of宏定义分析

转载来自:http://www.cnitblog.com/puppypyb/archive/2008/08/20/48172.aspx

一、#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )
1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型;
巧妙之处在于将0转换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址。
举例说明:
#include<stdio.h>
typedef struct _test
{
      char i;
      int j;
      char k;
}Test;
int main()
{
      Test *p = 0;
      printf("%p\n", &(p->k));
}
答案:00000008
自己分析:这里使用的是一个利用编译器技术的小技巧,即先求得结构成员变量在结构体中的相对于结构体的首地址的偏移地址,然后根据结构体的首地址为0,从而得出该偏移地址就是该结构体变量在该结构体中的偏移,即:该结构体成员变量距离结构体首的距离。在offsetof()中,这个member成员的地址实际上就是type数据结构中member成员相对于结构变量的偏移量。对于给定一个结构,offsetof(type,member)是一个常量,list_entry()正是利用这个不变的偏移量来求得链表数据项的变量地址。

二、container_of()
container_of() 来自\linux\kernel.h
内核中的注释:container_of - cast a member of a tructure out to the containing structure。
ptr: the pointer to the member.
type: the type of the container struct this is embedded in.
member:the name of the member within the truct.

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

GCC编译器使用了一些比较新的关键字,比如typeof,所以上面的代码是无法在 VC等编译器上通过

自己分析:
1.(type *)0->member为设计一个type类型的结构体,起始地址为0,编译器将结构体的起始的地址加上此结构体成员变量的偏移得到此结构体成员变量的偏移地址,由于结构体起始地址为0,所以此结构体成员变量的偏移地址就等于其成员变量在结构体内的距离结构体开始部分的偏移量。即:&(type *)0->member就是取出其成员变量的偏移地址。而其等于其在结构体内的偏移量:即为:(size_t)(& ((type *)0)->member)经过size_t的强制类型转换后,其数值为结构体内的偏移量。该偏移量这里由offsetof()求出。
2.typeof( ( (type *)0)->member )为取出member成员的变量类型。用其定义__mptr指针.ptr为指向该成员变量的指针。__mptr为member数据类型的常量指针,其指向ptr所指向的变量处。
3.(char *)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member))用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr -offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。
4.({ })这个扩展返回程序块中最后一个表达式的值。
      这就是从结构体某成员变量指针来求出该结构体的首指针。指针类型从结构体某成员变量类型转换为该结构体类型。

<think>好的,用户想了解container_of宏的用法、定义以及如何查找其定义,特别是C语言内核编程中的相关内容。首先,我需要回忆这个宏的基本结构和作用。记得container_ofLinux内核中广泛使用,用于通过结构体的成员指针获取整个结构体的指针。 接下来,用户提到了三个引用,其中引用1、2、3都给出了宏的定义,说明用户可能已经看过这些资料,但需要更清晰的解释。需要确保回答结构清晰,分点说明用法、定义和查找方法。 首先,解释container_of的作用。例如,在驱动开发中,经常需要从某个成员的指针(比如设备结构体中的链表节点)反向找到包含它的结构体实例。这时container_of就派上用场了。 然后,分析宏的定义。根据引用中的代码,宏使用了typeofoffsetof。需要解释每一部分的作用。比如,第一行声明一个指向成员的指针__mptr,并进行类型检查。第二行通过计算成员在结构体中的偏移量,用char*指针进行减法操作,得到结构体的起始地址。 关于用法,用户可能需要示例代码来说明。例如,定义一个结构体,然后通过其中一个成员找到结构体实例的地址。这里要注意代码的格式,用中文注释,确保用户理解每一步。 如何查找定义部分,用户可能想知道在内核源码中的位置。根据引用1,宏定义在include/linux/kernel.h中,但不同内核版本位置可能有变化。需要建议用户使用grep或IDE工具搜索,并提到可能依赖的其他头文件,比如stddef.h中的offsetof。 还要考虑用户可能的疑问,比如宏的安全性、类型检查机制,以及在内核编程中的实际应用场景。这些问题可以作为相关问题列出,帮助用户深入学习。 最后,检查是否符合系统级指令:行内公式用$...$,独立公式用$$...$$,语法正确,使用中文,生成相关问题,引用标识正确。确保没有使用Markdown,代码块用三个反引号包裹,结构清晰。</think>### container_of宏详解 #### 一、定义解析 container_of宏在Linux内核中的典型定义如下: ```c #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type, member) );}) ``` 该宏包含三个关键要素: 1. `typeof`运算符:获取成员变量的类型 2. `offsetof`宏:计算成员在结构体中的偏移量 3. 指针类型转换:通过地址运算定位父结构体 其数学表达式为: $$ \text{container\_addr} = \text{member\_ptr} - \text{offset}(member) $$ #### 二、核心用法 假设有结构体定义: ```c struct device { int id; struct list_head list; // 链表节点 char name[32]; }; ``` 当已知`list`指针时,可通过: ```c struct device *dev = container_of(ptr, struct device, list); ``` 反向获取包含该list节点的device结构体指针[^3] #### 三、实现原理 1. **类型安全检查**:`typeof`确保传入指针类型与成员类型匹配 2. **偏移量计算**:`offsetof(type, member)`展开为`(size_t)&((type *)0)->member`,利用空指针计算成员偏移 3. **地址运算**:将成员指针转换为char*进行精确字节偏移计算 #### 四、查找定义方法 1. **内核源码定位**: ```bash grep -rn "container_of" /usr/src/linux/include/linux/ ``` 通常在`include/linux/kernel.h`文件中[^1] 2. **代码分析工具**: - 使用VSCode等IDE的符号跳转功能 - 通过`ctags`/`cscope`建立索引数据库 #### 五、典型应用场景 1. 内核链表操作(list_head结构) 2. 设备驱动中通过子设备查找父设备 3. 内核对象管理系统(kobject) ```c // 示例:通过work_struct查找包含它的work_queue结构 struct work_queue { int priority; struct work_struct work; }; struct work_struct *ws = ...; struct work_queue *wq = container_of(ws, struct work_queue, work); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值