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

 更新时间:2021年07月14日 11:38:56   作者:叨陪鲤  
container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,这篇文章主要给大家介绍了关于linux内核编程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的类型仅此而已。至此基本结束

(三) 总结

       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()函数 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Linux工具之Nethogs按进程监控网络带宽的安装部署

    Linux工具之Nethogs按进程监控网络带宽的安装部署

    NetHogs是一个小型的net top工具,不像大多数工具那样拖慢每个协议或者是每个子网的速度而是按照进程进行带宽分组,这篇文章主要介绍了Linux工具Nethogs按进程监控网络带宽,值得收藏,需要的朋友可以参考下
    2019-07-07
  • CentOS 8设置自动更新的完整步骤

    CentOS 8设置自动更新的完整步骤

    这篇文章主要给大家介绍了关于CentOS 8设置自动更新的完整步骤,文中通过示例代码介绍的非常详细,对大家学习或者使用CentOS 8具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-11-11
  • Linux系统目录大小通过du命令获取实例

    Linux系统目录大小通过du命令获取实例

    在本篇文章里小编给大家整理的是一篇关于Linux系统目录大小通过du命令获取实例内容,需要的朋友们可以参考学习下。
    2020-11-11
  • apache You don''t have permission to access /test.php on this server解决方法

    apache You don''t have permission to access /test.php on thi

    这篇文章主要介绍了apache You don't have permission to access /test.php on this server解决方法,需要的朋友可以参考下
    2015-04-04
  • Apache+Weblogic实现URL转发

    Apache+Weblogic实现URL转发

    由于项目部署在Weblogic应用服务器上,用户访问的时候需要加端口号,这就非常的不友好了,所以又架设了Apache,使用URL转发方式来处理这个问题,本文是记录一下方法,给需要的小伙伴参考下
    2014-11-11
  • 详解linux下redis安装、启动与停止,redis做成服务

    详解linux下redis安装、启动与停止,redis做成服务

    这篇文章主要介绍了详解linux下redis安装、启动与停止,redis做成服务,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-12-12
  • Linux查看History记录加时间戳的小技巧

    Linux查看History记录加时间戳的小技巧

    今天小编就为大家分享一篇关于Linux查看History记录加时间戳的小技巧,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • linux less命令实例详解

    linux less命令实例详解

    在本篇文章了小编给大家整理了关于linux less命令详解的相关内容,需要的朋友们可以学习下。
    2020-02-02
  • 详解Linux误删用户家目录的恢复方法

    详解Linux误删用户家目录的恢复方法

    本篇文章主要介绍了详解Linux误删用户家目录的恢复方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • git bash配置ssh 登录 Linux的方法

    git bash配置ssh 登录 Linux的方法

    今天小编就为大家分享一篇git bash配置ssh 登录 Linux的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07

最新评论