Linux内核中的常用宏container_of其实很简单【转】
转自:http://blog.csdn.net/npy_lp/article/details/7010752
开发平台:Ubuntu11.04
编 译器:gcc version 4.5.2 (Ubuntu/Linaro4.5.2-8ubuntu4)
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。
Container_of的定义如下:
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
其实它的语法很简单,只是一些指针的灵活应用,它分两步:
第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。
其中的语法难点就是如何得出成员相对结构体的偏移量?
通过例子说明,如清单1:
- /* linux-2.6.38.8/include/linux/compiler-gcc4.h */
- #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
- /* linux-2.6.38.8/include/linux/stddef.h */
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- #include <stdio.h>
- struct test_struct {
- int num;
- char ch;
- float fl;
- };
- int main(void)
- {
- printf("offsetof(struct test_struct, num) = %d\n",
- offsetof(struct test_struct, num));
- printf("offsetof(struct test_struct, ch) = %d\n",
- offsetof(struct test_struct, ch));
- printf("offsetof(struct test_struct, fl) = %d\n",
- offsetof(struct test_struct, fl));
- return 0;
- }
说明,__builtin_offsetof(a,b)是GCC的内置函数,可认为它的实现与((size_t) &((TYPE *)0)->MEMBER)这段代码是一致的。
例子输出结果:
- offsetof(struct test_struct, num) = 0
- offsetof(struct test_struct, ch) = 4
- offsetof(struct test_struct, fl) = 8
其中代码难以理解的地方就是它灵活地运用了0地址。如果觉得&( (struct test_struct *)0 )->ch这样的代码不好理解,那么我们可以假设在0地址分配了一个结构体变量struct test_struct a,然后定义结构体指针变量p并指向a(struct test_struct *p = &a),如此我们就可以通过&p->ch获得成员ch的地址。由于a的首地址为0x0,所以成员ch的首地址为0x4。
最后通过强制类型转换(size_t)把一个地址值转换为一个整数。
分析完container_of的定义,接下来举两个例子来体会一下它的使用方法。
正确的例子,如清单2:
- /* linux-2.6.38.8/include/linux/compiler-gcc4.h */
- #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
- /* linux-2.6.38.8/include/linux/stddef.h */
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- /* linux-2.6.38.8/include/linux/kernel.h *
- * 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) );})
- #include <stdio.h>
- struct test_struct {
- int num;
- char ch;
- float fl;
- };
- int main(void)
- {
- struct test_struct init_test_struct = { 99, 'C', 59.12 };
- char *char_ptr = &init_test_struct.ch;
- struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);
- printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",
- test_struct->num, test_struct->ch, test_struct->fl);
- return 0;
- }
例子输出结果:
- test_struct->num = 99
- test_struct->ch = C
- test_struct->fl = 59.119999
不适当的例子,如清单3:
- /* linux-2.6.38.8/include/linux/compiler-gcc4.h */
- #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
- /* linux-2.6.38.8/include/linux/stddef.h */
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- /* linux-2.6.38.8/include/linux/kernel.h *
- * 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) );})
- #include <stdio.h>
- struct test_struct {
- int num;
- char ch;
- float fl;
- };
- int main(void)
- {
- char real_ch = 'A';
- char *char_ptr = &real_ch;
- struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);
- printf(" char_ptr = %p test_struct = %p\n\n", char_ptr, test_struct);
- printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",
- test_struct->num, test_struct->ch, test_struct->fl);
- return 0;
- }
例子输出结果:
- char_ptr = 0xbfb72d7f test_struct = 0xbfb72d7b
- test_struct->num = -1511000897
- test_struct->ch = A
- test_struct->fl = 0.000000
注意,由于这里并没有一个具体的结构体变量,所以成员num和fl的值是不确定的。
Linux内核中的常用宏container_of其实很简单【转】相关推荐
- (六)linux内核中的offsetof与container_of宏
参考: offsetof与container_of宏[总结] #define offsetof(type, member) (size_t)&(((type*)0)->member)#d ...
- linux内核函数 ffs,linux内核中的宏ffs(x)【转】
linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __ ...
- linux内核函数 ffs,linux内核中的宏ffs(x)
转自:https://www.cnblogs.com/fengeryi/p/3449720.html linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/incl ...
- Linux内核中的同步原语:自旋锁,信号量,互斥锁,读写信号量,顺序锁
Linux内核中的同步原语 自旋锁,信号量,互斥锁,读写信号量,顺序锁 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. Linux 内核中的同步原 ...
- Linux 内核中的 GCC 特性(zz)
from:http://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/ GCC 和 Linux 是出色的组合.尽管它们是独立的软件,但是 Linux ...
- Linux内核中64位除法函数do_div
使用asm/div64.h中宏do_div #include <asm/div64.h> unsigned long long x,y,result; unsigned long mod; ...
- Linux内核中max()宏的奥妙何在?(一)
Linux内核中max()宏的奥妙何在?(一) 1.max()宏那点事 在Linux内核中,有这样四个比较大小的函数,如下: max(x,y) //两个数求最大值 min(x,y) //两个数求最小值 ...
- Linux内核中max()宏的奥妙何在?(二)——大神Linus对这个宏怎么看?
最新max()宏 上回,我们在<Linux内核中max()宏的奥妙何在?(一)>一文中说到,在3.18.34版Linux内核源码中的max()宏,采用了GCC的扩展特性,可以避免一些错误. ...
- Linux 内核中的宏定义
Linux 内核中的宏定义 rtoax 日期 内核版本:linux-5.10.13 注释版代码:https://github.com/Rtoax/linux-5.10.13 __attribute__ ...
最新文章
- centos开启防火墙指定端口
- python 调用shell或windows命令
- CF1550F Jumping Around
- lucene 源码分析_Lucene分析过程指南
- jibx_Jibx Jersey2集成
- Redis3.2.5部署(单节点)
- 10个理由告诉你为何要学Java编程?
- docker+mysql创建用户名密码_docker构建私有仓库并设置仓库用户和密码
- windows下kangle虚拟主机-easypanel跑iis6.0开php空间并支持ZendOptimizer教程
- 基于web的网上书城网站设计与实现(SpringBoot ,Vue,MySQL )
- 重磅福利 | 知乎上赞同数最高的1000个回答2019最新版
- kappa一致性检验教程_一致性检验的几种方式--ICC、kappa、weighted kappa、Kendall
- 共话新基建,墨天轮数据库大咖讲坛第一期圆满成功!(附第二批中奖名单)...
- MTk kernel启动流程
- 360扫描出来html木马,你的电脑真的做好防护了吗?使用360安全卫士木马查杀一键扫描就知道...
- 学生来看我,我自我满足...........
- 通过SqlDbx导出*.sql
- 通过基于模型的系统工程简化复杂性案例研究
- Cena win8/win10配置
- webIx之表单提交
热门文章
- freebsd linux目录,FreeBSD和Linux如何互相访问文件系统
- 解锁三星bl锁有几种方法_解锁陶瓷砂磨机常见的几种机械密封损坏原因及处理方法发表...
- Java防止用户同一时间重复登录(包括异地登录)
- org.hibernate.LazyInitializationException: could not initialize proxy - no Session
- leader:你的代码太烂了我根本看不懂
- leetcode647 回文子串
- sql倒序查询语句_SQL丨1.基本查询语句复习
- clion编译器解决undefined reference to symbol ‘shm_open@@GLIBC_2.2.5‘
- Java提高篇 —— Java关键字之static的四种用法
- 4G发牌或提早 电信联通面临艰难抉择