神奇的container_of()宏

Linux内核的神奇的container_of()宏


1. 用途

container_of()宏可以跟据结构体成员的地址返回结构体的地址。

2. 定义

Linux内核中list即链表结构有个宏container_of(),其定义(linux-2.6.11/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) );})

相关的offsetof()宏定义(linux-2.6.11/include/linux/list.h)为:

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

3. 如何理解

3.1 offsetof()宏

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

我们一层层解析这个宏:

        ((TYPE *)0)        :  将0强制转换为指向TYPE类型的结构体的指针

        ((TYPE *)0)->MEMBER  :  通过上述结构体指针,得到结构体成员MEMBER

      &((TYPE *)0)->MEMBER  :  对结构体成员取地址操作,得到成员地址

  ((size_t) &((TYPE *)0)->MEMBER)    :  强制转化为size_t类型

这里面比较难以理解的是对0的相关操作,实际上编译器在解析这个宏的时候,并不会真的对0做以上操作,只是获取到该结构体的类型,然后将MEMBER成员在结构体内的偏移地址加上0后返回,即编译器返回的是MEMBER成员的结构体内偏移地址。可以使用以下代码验证:

 1 #include <stdio.h>
 2
 3 #define offsetof0(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 4 #define offsetof1(TYPE, MEMBER) ((size_t) &((TYPE *)1)->MEMBER)
 5
 6 struct data_stu{
 7     int data;
 8     char name[10];
 9 };
10
11 int main(void){
12     printf("data: %d\t", offsetof0(struct data_stu, data));
13     printf("name: %d.\n", offsetof0(struct data_stu, name));
14
15     printf("data: %d\t", offsetof1(struct data_stu, data));
16     printf("name: %d.\n", offsetof1(struct data_stu, name));
17
18     return 0;
19 }

运行结果:

    

3.2 container_of()宏

下面我们再来看看container_of()宏

#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})

宏的第一行定义了一个member类型的指针,并赋值为该结构体成员member的地址。听起来有点怪?

宏的第二行将mptr的地址减去其在结构体内的偏移,从而得到结构体的内存地址。

需要说明的几点:

  •  typeof(x)出自GCC, 返回x的类型。详细可参考GCC文档说明

    int a;
    typeof(a) b; //b is a int
  • 为何要定义mptr

   为了类型检查。

4. 参考文档

  参见大神文档 https://radek.io/2012/11/10/magical-container_of-macro/

原文地址:https://www.cnblogs.com/Freeee/p/12316242.html

时间: 2024-11-13 10:14:45

神奇的container_of()宏的相关文章

深入浅出实例解析linux内核container_of宏

做一件事情首先应该知道它的目的是什么. container_of的目的:如何通过结构中的某个变量获取结构本身的指针. 总体思路:假想一下,你的结构体中有好几个成员,你如何通过里面的"任一成员"获取整个结构体的首地址呢.container_of的做法就是通过typeof定义一个与"任一成员"同类型的指针变量pvar_a(假设变量名就是pvar_a),并让指针变量pvar_a指向这个"任一成员",然后用 "pvar_a的地址" 减

第十七天:APCS和container_of宏

APCS 全称:ARM 过程调用标准 如果要写用来与编译后的 C 连接的汇编代码,则必须使用 APCS. 今天的课程最终的两个目标:使用符合APCS标准的汇编写输出hello world  以及编写container_of宏 .这两个的推导过程比较复杂和具有跳跃性.结论的话要记住两个知识点,一:编写汇编函数的时候要对相应的寄存器进行保护.保护代码需要记住,每次写函数的时候都要用到.二:container_of实现了根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针的功能.以

C语言之offset_of宏和container_of宏

通过结构体整体变量来访问其中各个元素,本质上是通过指针方式来访问的,形式上是通过.的方式来访问的(这时候其实是编译器帮我们自动计算了偏移量). 1:offset_of宏 作用:计算结构体中某个元素和结构体首地址的偏移量(其实质是通过编译器来帮我们计算). 定义: #define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) 参数分析:TYPE是结构体类型,MEMBER是结构体中一个元素的元素名 返回值:member元素相对于整个结构体

C语言之offsetof宏和container_of宏

首先我们要明白一点通过结构体变量来访问结构体中的各个元素时,其本质上是 通过指针的方式来实现访问的,只不过是这个时候编译器帮自动帮我们计算了每个 元素与结构体起始地址之间的偏移量而已 一:offsetof宏: #define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) 1:参数与返回值分析: (1)TYPE是结构体类型,MEMBER是结构体中一个元素的元素名 (2)这个宏返回的是member元素相对于整个结构体变量的首地址的偏移量,

container_of宏定义解析

container_of宏,定义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 th

对offsetof、 container_of宏和结构体的理解

offsetof 宏 #include<stdio.h> #define offsetoff(type, member)      ((int)&((type*)0)->member) /* ((type*)0)->member 释义:声明一个相应类型的结构体指针,该指针指向0地址处.再通过该指针访问各元素.我们只要获取一个指针就能访问其内部的元素吗,可以这么搞?其实我是想联系全局和非全局变量,通过上面这个代码也许你不明白我要表达的意思.请继续慢慢看,直到本文后面,结合本文

container_of宏剖析

container_of宏剖析//该宏位于include/linux/kernel.h 1.定义格式 /** * 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 nam

container_of()宏

最近学习为Android添加编写内核驱动,遇到的第一个问题就是linux中大名鼎鼎的container_of()宏. container_of()是Linux内核中一个非常重要的宏,主要功能就是:根据结构体中一个域成员的地址获取整个结构体的地址. container_of()定义如下: 1 /** 2 * container_of - cast a member of a structure out to the containing structure 3 * @ptr: the pointe

linux中offsetof与container_of宏定义

linux内核中offsetof与container_of的宏定义 #define offsetof(TYPE, MEMBER)    ((size_t) &((TYPE *)0)->MEMBER) /** * container_of - cast a member of a structure out to the containing structure * @ptr:        the pointer to the member. * @type:       the type