#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的更多相关文章

  1. 剖析linux内核中的宏-----------offsetof

    offsetof用于计算TYPE结构体中MEMBER成员的偏移位置. #ifndef offsetof#define offsetof(TYPE, MEMBER) ((size_t) &((T ...

  2. linux内核中的宏ffs(x)

    linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __ ...

  3. KSM剖析——Linux 内核中的内存去耦合

    简介: 作为一个系统管理程序(hypervisor),Linux® 有几个创新,2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging)  允许这个系统管理程序通 ...

  4. Linux内核中的宏:__init and __exit

    ZZ FROM: http://blog.csdn.net/musein/article/details/742609 ======================================== ...

  5. (十)Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  6. Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  7. Linux内核中的常用宏container_of其实很简单【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...

  8. Linux内核中的fastcall和asmlinkage宏

    代码中看见:#define _fastcall 所以了解下fastcall -------------------------------------------------------------- ...

  9. Linux内核中SPI/I2c子系统剖析

    Linux内核中,SPI和I2C两个子系统的软件架构是一致的,且Linux内核的驱动模型都以bus,driver,device三种抽象对象为基本元素构建起来.下文的分析将主要用这三种抽象对象的创建过程 ...

随机推荐

  1. 巡风视图函数源码学习--view.py

    记录一下巡风扫描器view.py这个脚本里的视图函数的学习,直接在代码里面做的注释,里面有一些print 代码是为了把数据打印出来小白我自己加的,勿怪勿怪.可能存在一些理解错误和不到位的地方,希望大佬 ...

  2. CF1278C-Berry Jam-(前缀和)

    https://vjudge.net/problem/CodeForces-1278C 题意:有2n瓶果酱,中间有一个楼梯隔开,从中间往左或右两边清空果酱,使得两种果酱的数量相等,最少要清空多少瓶 思 ...

  3. 【CF280D】k-Maximum Subsequence Sum(大码量多细节线段树)

    点此看题面 大致题意: 给你一个序列,让你支持单点修改以及询问给定区间内选出至多\(k\)个不相交子区间和的最大值. 题意转换 这道题看似很不可做,实际上可以通过一个简单转换让其变可做. 考虑每次选出 ...

  4. 使用Python写yaml用例

    1.打开cmd,进入本机安装python的目录,执行   pip install pyyaml ,安装pyyaml第三方包. 2.在Pycharm中新建一个项目(已有的话就不需要啦) 新建yaml文件 ...

  5. 使用Vue封装暂无数据占位图组件

    1. 前言 在日常开发中,页面上肯定有展示数据的需求,但是当某些时候该展示数据的地方此时数据为空时,就会留下一片空白,对用户体验不是很好,那么接下来我们就封装一个空数据时的占位展示图,告诉用户此时用户 ...

  6. Ubuntu无法正常输入英文单引号符号 + 误删除package导致系统设置异常(解决方案)

    1 先说解决单引号的问题 写代码,遇到了输入英文单引号无法正常输入,需要按两次,而且不是竖向,而是斜的. 然后在寻找解决方案的过程中又遇到了把中文输入法搞得不能使用的问题.破费周折!!! 对Ubunt ...

  7. SQL 错误: ORA-65096: 公用用户名或角色名无效 65096. 00000 - "invalid common user or role name" *Cause: An attempt was made to create a common user or role with a name

    在Oracle SQL Developer中,试图创建RD用户时,出现了如下的错误: 在行: 上开始执行命令时出错 - 错误报告 - SQL 错误: ORA: 公用用户名或角色名无效 . - &quo ...

  8. 对象查询语言(OQL)的应用实例

    一.绪论 两个多星期前,我的导师布置了一道作业,就是利用对象查询语言(OQL)对常规的SQL需求进行求解.而对于我一个在面向对象数据库方面,经验可谓无足轻重的新手来说,确实难以下手.不用说,我肯定在拿 ...

  9. ros局部路径规划-DWA学习

    ROS的路径规划器分为全局路径和局部路径规划,其中局部路径规划器使用的最广的为dwa,个人理解为: 首先全局路径规划会生成一条大致的全局路径,局部路径规划器会把全局路径给分段,然后根据分段的全局路径的 ...

  10. nginx代理tcp请求

    1.概述 ngx_stream_core_module 这个module在nginx1.90后开始支持.开启nginx的tcp代理支持--with-stream=dynamic --with-stre ...