内核源码之 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) );
});
他的值是代码块最右边的表达式的值,这一点有点像逗号表达式,第一次见到这种用法。
到这里这个宏的解析算是完成了!
内核中的代码随便几行都覆盖了我知识点的盲区,非常细节,处于好奇研究了下这段代码。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于