C语言宏函数container of()怎么使用
本篇内容主要讲解“C语言宏函数container of()怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言宏函数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: 无符号整型)。
(二)内核编程的严谨性
#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, 但是如果去掉改行,那个就没有了,而这个警告恰恰是必须的(防止出错有不知道错误在哪里)。。。这严谨性可以吧
typeof( ((type *)0)->member )
它的作用是获取member的类型仅此而已。
到此,相信大家对“C语言宏函数container of()怎么使用”有了更深的了解,不妨来实际操作一番吧!这里是蜗牛博客网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
评论