• 售前

  • 售后

热门帖子
入门百科

linux内核编程container of()函数介绍

[复制链接]
墙和鸡蛋 显示全部楼层 发表于 2021-8-14 14:23:29 |阅读模式 打印 上一主题 下一主题
媒介

在linux 内核编程中,会常常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们如许的一般人就会绝望了(这一堆都是什么呀? 函数还可以如许界说??? 怎么另有0呢???  哎,算了,还是放弃吧。。。)。 这就是内核大佬们锋利的地方,随便两行代码就让我们猜疑人生,凡是都须要一个过程,慢慢来吧。

        其实,原理很简朴:  已知布局体type的成员member的地点ptr,求解布局体type的起始地点。
                  type的起始地点 = ptr - size      (这里须要都转换为char *,由于它为单位字节)。
       到此,该函数已经讲完,是不是很简朴??? 其实也不是,这里并没有提到size如何盘算,而令我们头晕的正是这里。
    好吧,先上container of函数原型:
  1. #define container_of(ptr, type, member) ({              \         
  2. const typeof( ((type *)0)->member ) *__mptr = (ptr);    \         
  3. (type *)( (char *)__mptr - offsetof(type,member) );})
复制代码
   其次为 offserof 函数原型:
  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
复制代码
怎么样,是不是很炫?  好吧,下面开始揭开面纱:
  (一)0 指针的使用    (自己给的名字,不知有木标题)

            让究竟说话:
  1. #include<stdio.h>
  2. struct test
  3. {
  4.         char i ;
  5.         int j;
  6.         char k;
  7. };
  8. int main()
  9. {
  10.         struct test temp;
  11.         printf("&temp = %p\n",&temp);   
  12.         printf("&temp.k = %p\n",&temp.k);
  13.         printf("&((struct test *)0)->k = %d\n",((int)&((struct test *)0)->k));
  14. }
复制代码
编译运行,可以得到如下效果:
  1. &temp = 0xbf9815b4
  2. &temp.k = 0xbf9815bc
  3. &((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() 函数的功能给讲完了:::
  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
复制代码
这次再看就顺眼了吧(底层为什么是如许我还是不懂。。。只知道如许确实可以) ,  以是offsetof()的作用就是求我们梦寐以求的size, 并以size_t形式返回(size_t: 无符号整型)。
(二) 内核编程的严谨性  
  1. #define container_of(ptr, type, member) ({              \         
  2. const typeof( ((type *)0)->member ) *__mptr = (ptr);    \         
  3. (type *)( (char *)__mptr - offsetof(type,member) );})
复制代码
   这里我们只看第二行:
  1. const typeof( ((type *)0)->member ) *__mptr = (ptr);  
复制代码
它的作用是什么呢? 其实没什么作用(勿喷勿喷,让我把话说完),但就形式而言 _mptr = ptr,  那为什么要要界说一个一样的变量呢??? 其实这正是内核人员的牛逼之处:如果开发者使用时输入的参数有标题:ptr与member范例不匹配,编译时便会有warnning, 但是如果去掉改行,谁人就没有了,而这个警告恰恰是必须的(防止堕落有不知道错误在那里)。。。这严谨性可以吧
  1. 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分别代表指针、范例、成员。

到此这篇关于linux内核编程container of()函数的文章就介绍到这了,更多相干linux container of()函数 内容请搜刮草根技能分享从前的文章或继续欣赏下面的相干文章盼望各人以后多多支持草根技能分享!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作