内核源码之 container_of(宏)

本贴最后更新于 1827 天前,其中的信息可能已经沧海桑田

内核源码之 container_of

在学习驱动的过程中发现一个很有意思的东西,就是 container_of 这个宏!
首先介绍下这个宏的功能:从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。
然后我们来看一下这个宏在内核源码中是如何定义:

/* include/linux/kernel.h: * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})

在这个宏中还使用了另外一个宏:

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

第一次看到这个宏的时候感觉很迷,不过这丝毫不能阻挡我把它弄懂的决心!接下来参考了几篇文章,差不多懂了。^^

container_of(ptr, type, member)先看看这三个参数,ptr 是你已经得到的一个成员变量的指针,type 是结构体类型,member 是 type 中 ptr 指向的那个成员变量的名称。
举个简单的例子:

struct student { char name[32]; int age; double score; }; struct student *zkw_p; struct student zkw= {"zkw", 21, 94}; int *p = &(zkw.age); //通过这个宏,传入p,以及它的结构体类型和对应的名称就得到了指向这个结构体指针。 zkw_p= container_of(p, struct student, age);
  • 仅仅知道如何使用时不够的,接下来看看到底是怎么实现的。
const typeof( ((type *)0)->member ) *__mptr = (ptr);

先看这一行,(type *)0 将 0 转化为结构体指针类型,然后访问 member 成员,接着用 typeof()得到((type *)0)->member 的类型,看到这里可能有人会问 typeof()是什么操作?我也是刚刚 get 到的(又是知识盲区啊!!)举个例子就懂了:

int var; typeof(var) var2;//等价于int var2; 很简单吧!

继续,typeof( ((type *)0)->member ) 很明了了吧!就是 member 成员的类型;这一整行代码就是 member 的类型的一个指针变量,然后把
ptr 指针赋值给了__mptr ,此时你一定会产生一个疑问,这操作有什么用,直接计算不好吗?这就是和大佬的差距啊,这是考虑到编程人员在传参时 ptr 和 member 类型匹配不上,加上这句之后类型出错之后再编译过程中编译会给出警告。(这设计很巧妙!)

(type *)( (char *)__mptr - offsetof(type,member) );

这行代码得先说下 offsetof 这个宏:

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

TYPE 结构体,MEMBER 成员变量,相当于把结构体放在 0 地址处,然后去取成员变量的地址,取出地址再转化整 size_t 就是偏移的字节数;

__mptr 减去偏移量那么就得到了结构体的首地址。

还有一点,就是你把这个宏展开后你会发现长相比较奇特:
比如:

var = ({ const typeof( ((struct student *)0)->age ) *__mptr = (p); (struct student *)( (char *)__mptr - ((size_t) &((struct student *)0)->age) ); });

他的值是代码块最右边的表达式的值,这一点有点像逗号表达式,第一次见到这种用法。

到这里这个宏的解析算是完成了!

内核中的代码随便几行都覆盖了我知识点的盲区,非常细节,处于好奇研究了下这段代码。

  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    954 引用 • 944 回帖
  • 内核
    10 引用 • 14 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 2 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2040 回帖 • 1 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    24 引用 • 242 回帖
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 40 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 11 关注
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 34 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • OneNote
    1 引用 • 3 回帖
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    98 引用 • 367 回帖
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    44 引用 • 208 回帖
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    497 引用 • 934 回帖 • 1 关注
  • OnlyOffice
    4 引用 • 17 关注
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖
  • 安全

    安全永远都不是一个小问题。

    199 引用 • 818 回帖
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖
  • Hibernate

    Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

    39 引用 • 103 回帖 • 728 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    77 引用 • 37 回帖
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    326 引用 • 1395 回帖
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 661 关注
  • Excel
    31 引用 • 28 回帖
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    181 引用 • 400 回帖 • 1 关注
  • RemNote
    2 引用 • 16 回帖 • 25 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    10037 引用 • 45613 回帖 • 70 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 4 关注