标签:链表 offset char src alt line https div efi
container_of()宏可以跟据结构体成员的地址返回结构体的地址。
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)
#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 }
运行结果:
下面我们再来看看container_of()宏
#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
宏的第一行定义了一个member类型的指针,并赋值为该结构体成员member的地址。听起来有点怪?
宏的第二行将mptr的地址减去其在结构体内的偏移,从而得到结构体的内存地址。
需要说明的几点:
int a; typeof(a) b; //b is a int
为了类型检查。
参见大神文档 https://radek.io/2012/11/10/magical-container_of-macro/
标签:链表 offset char src alt line https div efi
原文地址:https://www.cnblogs.com/Freeee/p/12316242.html