剖析linux内核中的宏---------container_of
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
作用:通过结构体成员变量member的地址,反推出member成员所在结构体变量的首地址,ptr指向成员变量member。
解析:
1)({ })是何方神圣?
({ })是GNU C编译器的语法扩展
({ })与逗号表达式类似,结果作为最后一个语句的值

2)typeof是一个关键字吗?
typeof是GNU C编译器的特有的关键字
typeof只在编译期生效,用于得到变量的类型
3)最后的原理

首先通过offsetof计算出成员变量c在结构体中的偏移量;
pc是指向结构体中成员变量c的指针;
(char *)pc 将pc指针强制类型转换为char *,目的就是为了做指针运算
所实现的就是通过结构体中的一个成员变量的地址反推结构体变量的首地址。
现通过代码来说明,

结构体变量s的值就是结构体变量的首地址,通过container_of也可以得到结构体变量的首地址,两者打印出来的值是相同的。
细心的同学可能会发现,container_of宏中的第二行代码有什么用呢,现在我们就用代码说明,它到底有何用处?

我们将宏中的第二行代码删掉,运行结果同样正确,你心中是否会这样想:这行代码完全可以删掉,因为它对运行结果没有什么影响。如果你这么想,那么请继续往下看:
首先使用我们修改的这个宏,即将第二行代码删掉:

编译过后仅仅告诉我们pc指针没有使用,然后接下来运行。

从中可以看出能够正常的运行,但是运行结果不是我们想要的结果,是不对的。
现在我们用内核提供给我们的宏,即没有经过修改的宏:

在进行编译的时候,多出现了一个警告,提示我们类型不兼容。
所以container_of宏中的第二行代码,是为了做类型检查的。
container_of的功能只能用宏来实现,宏其实是由预处理器在编译的时候来进行处理的。预处理器做的是单纯的文本替换,不会进行任何的类型检查。这就有可能导致我们在编写代码的时候由粗心大意而造成的错误,就像上面的这个错误误用了pi指针。这时候,为了增加代码的安全性,为了有一点点的类型检查,所以在linux内核中该宏的定义中加上了const typeof(((type *)0)->member) * __mptr = (ptr);这条语句。
可能还有疑问?
1)不使用({}),使用逗号表达式能否实现 不可以,因为里面有指针的定义,不能存在于逗号表达式中
2)(type *)0)->member 访问了0地址,会导致程序的崩溃吗?
typeof是在编译期有效,在编译期间就可以拿到成员变量的类型了,不用等到运行期间了。在运行的时候,该条语句就不存在了,因此不会导致程序的崩溃。
剖析linux内核中的宏---------container_of的更多相关文章
- 剖析linux内核中的宏-----------offsetof
offsetof用于计算TYPE结构体中MEMBER成员的偏移位置. #ifndef offsetof#define offsetof(TYPE, MEMBER) ((size_t) &((T ...
- linux内核中的宏ffs(x)
linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __ ...
- KSM剖析——Linux 内核中的内存去耦合
简介: 作为一个系统管理程序(hypervisor),Linux® 有几个创新,2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging) 允许这个系统管理程序通 ...
- Linux内核中的宏:__init and __exit
ZZ FROM: http://blog.csdn.net/musein/article/details/742609 ======================================== ...
- (十)Linux内核中的常用宏container_of
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...
- Linux内核中的常用宏container_of
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...
- Linux内核中的常用宏container_of其实很简单【转】
转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...
- Linux内核中的fastcall和asmlinkage宏
代码中看见:#define _fastcall 所以了解下fastcall -------------------------------------------------------------- ...
- Linux内核中SPI/I2c子系统剖析
Linux内核中,SPI和I2C两个子系统的软件架构是一致的,且Linux内核的驱动模型都以bus,driver,device三种抽象对象为基本元素构建起来.下文的分析将主要用这三种抽象对象的创建过程 ...
随机推荐
- 忘记IBM服务器的登录IP
问题描述: 一台服务器安装了winserver2003系统,经过漫长的加电启动,能进入到win2003的登录界面,提示ctrl+alt+del登录界面,但是发现键盘失灵了,无法键入ctrl+alt+d ...
- Re-androideasy
题目地址 https://dn.jarvisoj.com/challengefiles/androideasy.apk.17e528e9498d4ae25dc82ad43730a03d 先看看功能 然 ...
- 遗传算法求解旅行商(TSP)问题 -- python
参考资料: 遗传算法解决TSP旅行商问题(附:Python实现) 遗传算法详解(GA)(个人觉得很形象,很适合初学者) from itertools import permutations impor ...
- 小程序-tabBar简易版
<!-- 结构 --> <view class="wrapper"> <block wx:for="{{desc}}"> & ...
- Excel已损坏,无法打开
突然之间,很多EXCEL文件打开时报错:"已损坏,无法打开",这些文件共同点是从邮件中下载而来,这些文件可能面临着安全威协,原来是软件设置了受保护的视图,取消即可.
- Educational Codeforces Round 69 (Rated for Div. 2) C. Array Splitting 水题
C. Array Splitting You are given a sorted array
- 9.29 csp-s模拟测试55 联+赛+题
T1 联 $n$最大到$1e18$,根本没法做,但$m$只有$1e5$,发现有很多区间是一起动的,或者根本没动,所以可以把区间离散化掉,然后线段树区间修改,对于第三种修改,只需要把它分解成一段一段相同 ...
- uni-app 环境配置,uni.request封装,接口配置,全局配置,接口调用的封装
1.环境配置 (可参考uni-官网的环境配置) common文件夹下新建config.js let url_config = "" if(process.env.NODE_ENV ...
- Docker系列之学习笔记
一.Docker简介 1.1.Docker架构 Docker 使用客户端-服务器 (C/S) 架构模式,分为Docker守护进程和客户端,Docker 客户端,实际上是 docker 的二进制程序,D ...
- jQuery 源码解析(七) jQuery对象和DOM对象的互相转换
jQuery对象是一个类数组对象,它保存的是对应的DOM的引用,我们可以直接用[]获取某个索引内的DOM节点,也可以用get方法获取某个索引内的DOM节点,还可以用toArray()方法把jQuery ...