container_of宏剖析
container_of宏剖析
//该宏位于include/linux/kernel.h
1.定义格式
/**
* container_of - cast a member of a structure 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 struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
作用:就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。
例:
struct demo_struct
{
type1 member1;
type2 member2;
type3 member3;
}
struct demo_struct demo1,*pdemo;
type2 * demo_member2=demo1.member2;
如果要得到demo1的指针,可以使用该宏:
pdemo=container_of(demo_member2,struct demo_struct,member2);
2.宏运行机理解析
typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型。将上例中的宏按照宏定义进行展开,如下:
1 pdemo=({\
2 const typeof(((struct demo_struct *)0)->member2) *__mptr=(demo_member2); \
3 (struct demo_struct *)((char *)__mptr-offsetof(struct demo_struct, member2));\
4 })
从上面定义来看,代码中的第2行的作用是首先使用typeof获取结构体域变量member2的类型为type2,然后定义了一个type2指针类型的临时变量__mptr,并将实际结构体变量中的域变量的指针demo_member2的值赋给临时变量__mptr。
第2行代码实际上类似下面定义:
const type2 * __mptr=demo_member2;
这里((struct demo_struct *)0)比较巧妙,它指的是struct demo_struct型变量地址为基地址,偏移量为0的地址,实际上就是struct demo_struct型变量地址。
第3行代码中,(char *)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member) )用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr - offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。
其中,offsetof宏定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE *)0)->MEMBER)
可以看出,该宏就是计算出TYPE变量中MEMBER成员基地址。该宏运行机理如下:
l ( (TYPE *)0 )将零转型为TYPE类型指针;
l ((TYPE *)0)->MEMBER访问结构中的数据成员;
l &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;
l (size_t)(&(((TYPE*)0)->MEMBER))结果转换类型。
该宏巧妙之处在于将0转换成(TYPE*),如果结构体以内存空间首地址0作为起始地址,则成员地址自然为偏移地址;
__mptr - offsetof(struct demo_struct, member2)
type1 member1
type2 member2
type3 member3
offsetof(type,member)__mptr
__mptr - offsetof(struct demo_struct, member2)
type1 member1
type2 member2
type3 member3
offsetof(type,member)__mptr
还有一篇文章
在linux内核中经常可以看到container_of的身影,也是linux引以为豪的地方之一了。《linux设备驱动开发详解》132页对container_of的作用作了说明——通过结构体成员的指针找到这个成员所在结构体的指针。但没有具体分析它是怎么实现的。
下面我们先看看这个宏的定义:
/**
* container_of - cast a member of a structure 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 struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
参数ptr是结构体typ的成员member的指针,我们很多时候希望得到结构体type的起始地址,也就是type的指针。
假设这个type在内存中的存储模型如下:
type
|----------|
| |
| |
|----------|
ptr->| member --|
|----------|
| |
| |
|----------|
这里,我们拆开来就好理解了:
首先,(type *)0)是把0地址转化为TYPE结构的指针(这里把0换成其它值也是一样的);
((type *)0)->member type结构体中的member成员;
typeof( ((type *)0)->member ) 返回member的类型;
const typeof( ((type *)0)->member ) *__mptr = (ptr); 用上面这个类型定义一个指针__mptr,并把ptr赋值给它;
(char *)__mptr 把__mptr转化成char型指针;
offsetof宏定义在[include/linux/stddef.h]中定义为:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
这里,说明一下这个宏,((size_t) &((TYPE *)0)->MEMBER)把0地址转化为TYPE结构的指针,然后获取该结构中MEMBER成员的指针,并将其强制转换为size_t类型。于是,由于结构从0地址开始定义,因此,这样求出的MEMBER成员地址,实际上就是它在结构中的偏移量。这也显示出了C语言中指针的强大。因为,在某个体系结构下实现的libc,结构中各个成员的偏移总是可以预见的。
现在有了member成员在type结构体中的偏移量,又有了指向member的指针__mptr,自然就可以计算出type结构的起始地址了。
小小一个宏就包括了这么多精华,可见linux的博大。
container_of宏剖析的更多相关文章
- Linux内核中container_of宏的详细解释
上一节拒绝造轮子!如何移植并使用Linux内核的通用链表(附完整代码实现)我们在分析Linux内核链表的时候注意到内核在求解结构体偏移的时候巧妙的使用了container_of宏定义,今天我们来详细剖 ...
- linux中offsetof与container_of宏定义
linux内核中offsetof与container_of的宏定义 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->M ...
- (转)offsetof与container_of宏[总结]
1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...
- container_of宏定义分析---linux内核
问题:如何通过结构中的某个变量获取结构本身的指针??? 关于container_of宏定义在[include/linux/kernel.h]中:/*_** container_of - cast a ...
- 内核中container_of宏的详细分析【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637597.html 内核中container_of宏的详细分析 16年2月28日09:00:37 内核中 ...
- offsetof与container_of宏[总结]
1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...
- container_of宏
title: container_of宏 date: 2019/7/24 15:49:26 toc: true --- container_of宏 解析 在linux链表结构中有这样一个宏,通过成员变 ...
- offsetof与container_of宏分析
offsetof宏:结构体成员相对结构体的偏移位置 container_of:根据结构体成员的地址来获取结构体的地址 offsetof 宏 原型: #define offsetof(TYPE, MEM ...
- typeof, offsetof, container_of宏
container_of宏实现如下: #define container_of(ptr, type, member) ({ \ )->member ) *__mptr = (ptr); \ (t ...
随机推荐
- Sdut 2165 Crack Mathmen(数论)(山东省ACM第二届省赛E 题)
Crack Mathmen TimeLimit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Since mathmen take security ...
- php 商务网站购物车联动地址
数据表如下: CREATE TABLE IF NOT EXISTS `china` (`region_id` smallint(5) unsigned NOT NULL, `parent_id` s ...
- Extjs发票管理系统
技术特点:Extjs框架,三层架构,Ajax,json 1.仿office2007菜单.介面美观大方,可动态更改皮肤保存至cookie. 2,json数据源与实体类的相互转换. 3.可下载桌面版登录方 ...
- 快速理解webStroage
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- USB驱动能力有限
笔者用USB接一个单片机最小系统,再从单片机最小系统引出电源线接一个数字电路模块.当后边两部分的功率较大时,就会引起USB电压的下降,甚至到3V左右.电压的下降就会使单片机或者数字电路部分芯片不能正常 ...
- C语言2048
这段时间google上有个小游戏挺火的,我也很喜欢,业余时间做个C语言版的. 老规矩先上干货: http://files.cnblogs.com/GhostZCH/2048.rar (.c & ...
- NOI冲刺计划2
吐槽:距离上一次写计划还没有一个月呢,咋又喊要重写捏?可以直接从上一次的计划粘上个一大半. bzoj刷题速度还是在计划之内的,这大半个月中,我bzoj刷进500道,知识方面主要是把莫比乌斯反演系统性的 ...
- hdu 4111 Alice and Bob
组合游戏题: 组合游戏的规则: 1.必败态的所有后继都是必胜态: 2.必胜态最少有一个必败的后继: 这里的必胜态是f[1][0][0][0]; 其中f[a][b][c][d]表示有a个1,b个2,c个 ...
- Windows Xp Home Edition 安装IIS组件
问题描述: 在虚拟机(操作系统是Windows Xp Home Edition)中安装Sql Server 2005的时候警告缺少IIS相关组件,控制面板"添加/删除组件"中也没有 ...
- QLGame 2D Engine编写环境搭建
QLGame 2D Engine编写 (win7环境搭建) 广州麒麟网络工作室,计划制作一款2d game engine,基于opengl(es)平台,暂时支持android,以后考虑支持linux, ...