神奇的container_of()宏
Posted freeee
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了神奇的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 ", offsetof0(struct data_stu, data)); 13 printf("name: %d. ", offsetof0(struct data_stu, name)); 14 15 printf("data: %d ", offsetof1(struct data_stu, data)); 16 printf("name: %d. ", 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/
以上是关于神奇的container_of()宏的主要内容,如果未能解决你的问题,请参考以下文章