container of()函数简介
在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义??? 怎么还有0呢??? 哎,算了,还是放弃吧。。。)。 这就是内核大佬们厉害的地方,随便两行代码就让我们怀疑人生,凡是都需要一个过程,慢慢来吧。
其实,原理很简单: 已知结构体type的成员member的地址ptr,求解结构体type的起始地址。
type的起始地址 = ptr - size (这里需要都转换为char *,因为它为单位字节)。
到此,该函数已经讲完,是不是很简单??? 其实也不是,这里并没有提到size如何计算,而令我们头晕的正是这里。
好吧,先上container of函数原型:
#define container_of(ptr, type, member) ({              \
const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
(type *)( (char *)__mptr - offsetof(type,member) );})
其次为 offserof 函数原型:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)怎么样,是不是很炫? 好吧,下面开始揭开面纱:
(一)0 指针的使用 (自己给的名字,不知有木问题)
让事实说话:
#include<stdio.h>
struct test
{
	char i ;
	int j;
	char k;
};
int main()
{
	struct test temp;
	printf("&temp = %p\n",&temp);
	printf("&temp.k = %p\n",&temp.k);
	printf("&((struct test *)0)->k = %d\n",((int)&((struct test *)0)->k));
}编译运行,可以得到如下结果:
&temp = 0xbf9815b4
&temp.k = 0xbf9815bc
&((struct test *)0)->k = 8
什么意思看到了吧,自定义的结构体有三个变量:i,j,k。 因为有字节对齐要求,所以该结构体大小为4bytes * 3 =12 bytes. 而&((struct test *)0)->k 的作用就是求 k到结构体temp起始地址的字节数大小(就是我们的size)。在这里0被强制转化为struct test *型, 它的作用就是作为指向该结构体起始地址的指针,就是作为指向该结构体起始地址的指针,就是作为指向该结构体起始地址的指针, 而&((struct test *)0)->k 的作用便是求k到该起始指针的字节数。。。其实是求相对地址,起始地址为0,则&k的值便是size大小(注:打印时因为需要整型,所以有个int强转)所以我们便可以求我们需要的 size 了 。 好吧,一不小心把 offsetof() 函数的功能给讲完了:::
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)这次再看就顺眼了吧 (底层为什么是这样我还是不懂。。。只知道这样确实可以) ,  所以offsetof()的作用就是求我们梦寐以求的size, 并以size_t形式返回(size_t: 无符号整型)。
(底层为什么是这样我还是不懂。。。只知道这样确实可以) ,  所以offsetof()的作用就是求我们梦寐以求的size, 并以size_t形式返回(size_t: 无符号整型)。
(二) 内核编程的严谨性
#define container_of(ptr, type, member) ({              \
const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
(type *)( (char *)__mptr - offsetof(type,member) );})这里我们只看第二行:
const typeof( ((type *)0)->member ) *__mptr = (ptr);  它的作用是什么呢? 其实没什么作用(

 勿喷勿喷,让我把话说完),但就形式而言 _mptr = ptr,  那为什么要要定义一个一样的变量呢??? 其实这正是内核人员的牛逼之处:如果开发者使用时输入的参数有问题:ptr与member类型不匹配,编译时便会有warnning, 但是如果去掉改行,那个就没有了,而这个警告恰恰是必须的(防止出错有不知道错误在哪里)。。。这严谨性可以吧
勿喷勿喷,让我把话说完),但就形式而言 _mptr = ptr,  那为什么要要定义一个一样的变量呢??? 其实这正是内核人员的牛逼之处:如果开发者使用时输入的参数有问题:ptr与member类型不匹配,编译时便会有warnning, 但是如果去掉改行,那个就没有了,而这个警告恰恰是必须的(防止出错有不知道错误在哪里)。。。这严谨性可以吧


typeof( ((type *)0)->member )它的作用是获取member的类型仅此而已。至此基本结束
(三) 总结
container_of(ptr, type,member)函数的实现包括两部分:
1. 判断ptr 与 member 是否为同意类型
2. 计算size大小,结构体的起始地址 = (type *)((char *)ptr - size) (注:强转为该结构体指针)
现在我们知道container_of()的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。
    container_of(ptr,type,member),这里面有ptr,type,member分别代表指针、类型、成员。
container of()函数简介的更多相关文章
- 转"container of()函数简介"链接地址
		https://blog.csdn.net/s2603898260/article/details/79371024 提示关键字: 指针0的使用 typeof的使用 
- linux进程编程:子进程创建及执行函数简介
		linux进程编程:子进程创建及执行函数简介 子进程创建及执行函数有三个: (1)fork();(2)exec();(3)system(); 下面分别做详细介绍.(1)fork() 函数定 ... 
- Linux Shell系列教程之(十五) Shell函数简介
		本文是Linux Shell系列教程的第(十五)篇,更多Linux Shell教程请看:Linux Shell系列教程 函数可以将一个复杂功能划分成若干模块,从而使程序结构更加清晰,代码重复利用率更高 ... 
- 【液晶模块系列基础视频】4.5.X-GUI图形界面库-进度条等函数简介
		[液晶模块系列基础视频]4.5.X-GUI图形界面库-进度条等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ... 
- 【液晶模块系列基础视频】4.4.X-GUI图形界面库-画tab函数简介
		[液晶模块系列基础视频]4.4.X-GUI图形界面库-画tab函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ... 
- 【液晶模块系列基础视频】4.3.X-GUI图形界面库-画box函数简介
		[液晶模块系列基础视频]4.3.X-GUI图形界面库-画box函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ... 
- 【液晶模块系列基础视频】4.2.X-GUI图形界面库-画矩形函数简介
		[液晶模块系列基础视频]4.2.X-GUI图形界面库-画矩形函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址: ... 
- 【液晶模块系列基础视频】4.1.X-GUI图形界面库-画线画圆等函数简介
		[液晶模块系列基础视频]4.1.X-GUI图形界面库-画线画圆等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地 ... 
- [转]SQLITE3 C语言接口 API 函数简介
		SQLITE3 C语言接口 API 函数简介 说明:本说明文档属作者从接触 SQLite 开始认识的 API 函数的使用方法, 由本人翻译, 不断更新. /* 2012-05-25 */ int sq ... 
随机推荐
- ABC165C题解
			题目 看题目的时候一脸懵,直到看见数据范围 \[N \le 10,\; M \le 10,\; Q \le 50 \] 之后才意识到问题的严重性. 毕竟数据如此的小,我们完全可以用阶乘复杂度算法卡过去 ... 
- Bugku-web-秋名山老司机
			计算式子的值然后使用post方法传值.直接脚本跑. import requestsimport reurl = "http://123.206.87.240:8002/qiumingshan ... 
- Java注解如何对属性动态赋值
			学而不思则罔,思而不学则殆 前言 大家都用过Spring的@Value("xxx")注解,如果没有debug过源码的同学对这个操作还是一知半解,工作一年了学了反射学了注解,还是不会 ... 
- 用Matlab求解微分方程
			用Matlab求解微分方程 解微分方程有两种解,一种是解析解,一种是数值解,这两种分别对应不同的解法 解析解 利用dsolve函数进行求解 syms x; s = dsolve('eq1,eq2,.. ... 
- SpringBoot开发十九-添加评论
			需求介绍 熟悉事务管理,并且应用到添加评论的功能. 数据层:增加评论数据,修改帖子的评论数量 业务层:处理添加评论的业务,先增加评论再更新帖子的评论数量(因为用到了两个DML操作所以要用到事务管理) ... 
- SpringBoot 整合 SpringSecurity 梳理
			文档 Spring Security Reference SpringBoot+SpringSecurity+jwt整合及初体验 JSON Web Token 入门教程 - 阮一峰 JWT 官网 Sp ... 
- Docker源码安装附内网镜像安装演示
			Docker源码安装附内网镜像安装演示 系统版本要求 当前系统版本:CentOS Linux release 7.9.2009 (Core) 内核版本:3.10.0-1160.el7.x86_64 注 ... 
- 题解 w
			传送门 一直觉得有点后效性什么的,也不知道怎么写 这题什么时候再康一遍,第一次见这个样子的树形DP,是个树上带不定权边的DP(??? 这里能树形DP的原因好像是在这里所有子节点的状态都能表示出来 还有 ... 
- SSM自学笔记(二)
			3.SpringMVC入门 1.Spring与Web环境集成 1.1 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplication ... 
- VMware上安装的Ubuntu不显示全屏解决方法
			花费了好一会才把电脑上的Vmware装上,把Ubuntu装到虚拟机上,谁知道Ubuntu不显示全屏,我调了分辨率,奈何Ubuntu里面固定的分辨率没有跟我电脑匹配的,然后开始寻找解决方法,在网上找了很 ... 
