首页 > 其他分享 >container of()函数简介

container of()函数简介

时间:2022-08-26 17:49:35浏览次数:70  
标签:container 函数 简介 struct member type ptr size

      在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 函数原型:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 

  怎么样,是不是很炫?  好吧,下面开始揭开面纱:

  (一)0 指针的使用    (自己给的名字,不知有木问题)

            让事实说话:

  1.   #include<stdio.h>
  2.    
  3.   struct test
  4.   {
  5.   char i ;
  6.   int j;
  7.   char k;
  8.   };
  9.    
  10.   int main()
  11.   {
  12.   struct test temp;
  13.   printf("&temp = %p\n",&temp);
  14.   printf("&temp.k = %p\n",&temp.k);
  15.   printf("&((struct test *)0)->k = %d\n",((int)&((struct test *)0)->k));
  16.    
  17.   }

 编译运行,可以得到如下结果:

  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() 函数的功能给讲完了:::

 

#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) );})
    这里我们只看第二行:
const typeof( ((type *)0)->member ) *__mptr = (ptr);  
 

  它的作用是什么呢? 其实没什么作用(尴尬尴尬尴尬勿喷勿喷,让我把话说完),但就形式而言 _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,函数,简介,struct,member,type,ptr,size
From: https://www.cnblogs.com/xuanmiao363/p/16628347.html

相关文章

  • SparkCore系列(四)函数大全
    有了上面三篇的函数,平时开发应该问题不大了。这篇的主要目的是把所有的函数都过一遍,深入RDD的函数RDD函数大全数据准备        val sparkconf = new Spa......
  • python3 函数 定义函数与切片
     如果我们要计算一个圆的面积,就是3.14*r*r,如果每次就算,则每次都要写一遍,就很麻烦,所以有了函数,我们就可以通过调用函数的方法,直接使用就行了。 这里我们可以访问 ......
  • 如何把thinkphp5的项目迁移到阿里云函数计算来应对流量洪峰?
    原文链接:https://developer.aliyun.com/article/9827461.为什么要迁移到阿里云函数?我的项目是一个节日礼品领取项目,过节的时候会有短时间的流量洪峰。平时访问量很低。......
  • Jetty简介
    1、Jetty是什么? Jetty是一个开源的servlet容器,它为基于Java的web容器,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人......
  • Lazars常用函数
    var i: Integer; Row: String; Parts: TStringArray; S1, S2, S3, S4: String;begin Row :=  '51,40,45,44,44,40,'; Parts......
  • 使用函数计算自定义运行时快速部署一个 SpringBoot 项目 | 文末有礼
    作者:谱一段风华笔墨什么是函数计算阿里云函数计算FC是事件驱动的全托管计算服务。使用函数计算,您无需采购与管理服务器等基础设施,只需编写并上传代码。函数计算为您准......
  • 【C标准库】详解strerror函数
    创作不易,感谢支持strerror头文件:string.h描述:strerror()函数接受一个参数:errnum,它是一个表示错误代码的整数值。此函数将错误代码转换为说明错误的合适字符串指针并返......
  • 向量距离与相似度函数
    假设当前有两个nn维向量xx和yy (除非特别说明,本文默认依此写法表示向量),可以通过两个向量之间的距离或者相似度来判定这两个向量的相近程度,显然两个向量之间距离越小,相似......
  • Kubernetes Container、Pod、Namespace内存及CPU限制
        如果运行的容器没有定义资源(memory、CPU)等限制,那么该容器可以使用宿主机的最大可用资源,直到无资源可用而触发宿主机(OOMKiller),为保证容器资源合理利用,需要在nam......
  • python中常见的几个函数
    functionuselen()用来求元组利润表或者字符串等的长度str()将数据转化成字符串类型......