宏函数作用
container_of宏的作用是通过结构体内某个成员变量的地址和该变量名,以及结构体类型。找到该主结构体的地址。这里使用的是一个利用编译器技术的小技巧,即先求得结构成员在结构中的偏移量,然后根据成员变量的地址反过来得出主结构体的地址
原型
#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)
参数解释:
宏分解
typeof
首先看下typeof,是用于返回一个变量的类型,这是GCC编译器的一个扩展功能,也就是说typeof是编译器相关的。既不是C语言规范的所要求,也不是某个标准的一部分。例
#include<stdio.h>
#include<string.h>
typedef struct student
{
int age;
char name[128];
}Student_t;
int main()
{
Student_t stu;
stu.age=18;
strncpy(stu.name,"qingmu",6);
typeof(stu.age) xx=100;
typeof(stu.name) yy="aaa";
printf("xx is : %d \nyy is : %s \n", xx,yy);
return 0;
}
执行结果:
xx is : 100
yy is : aaa
const typeof(((type )0)->member)__mptr = (ptr)
这句代码意思是用typeof()获取结构体里member成员属性的类型,然后定义一个该类型的临时指针变量__mptr,并将ptr所指向的member的地址赋给__mptr;
offsetof(type, member))
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
size_t是标准C库中定义的,在32位架构中被普遍定义为:typedef unsigned int size_t;
而在64位架构中被定义为:typedef unsigned long size_t;
为了使程序有很好的移植性,因此内核使用size_t和,而不是int,unsigned。
((size_t) &((TYPE*)0)->MEMBER) 结合之前的解释,我们可以知道这句话的意思就是求出MEMBER相对于0地址的一个偏移值。
#include<stdio.h>
#include<string.h>
typedef struct student
{
int age;
char name[128];
int id;
}Student_t;
int main()
{
Student_t stu;
stu.age=18;
strncpy(stu.name,"qingmu",6);
stu.id=100;
printf("age addr : %p\n",&stu.age);
printf("name addr :%p\n",&stu.name);
printf("name addr :%p\n",&stu.id);
printf("age 具结构体首地址的偏移 = %d\n",((int)&((struct student *)0)->age));
printf("name 具结构体首地址的偏移 = %d\n",((int)&((struct student *)0)->name));
printf("id 具结构体首地址的偏移 = %d\n",((int)&((struct student *)0)->id));
return 0;
}
运行结果:
age addr : 0x7fff44a10e80
name addr :0x7fff44a10e84
name addr :0x7fff44a10f04
age 具结构体首地址的偏移 = 0
name 具结构体首地址的偏移 = 4
id 具结构体首地址的偏移 = 132
(type *)((char *)__mptr - offsetof(type, member))
这句话的意思就是,把 __mptr 转换成 char * 类型, 因为 offsetof 得到的偏移量是以字节为单位。 两者相减得到结构体的起始位置, 再强制转换成 type 类型。例
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
typedef struct student
{
int age;
char name[128];
int id;
}Student_t;
int main()
{
Student_t *sptr = NULL;
Student_t stu;
stu.age=18;
strncpy(stu.name,"qingmu",6);
stu.id=100;
sptr = container_of(&stu.age,Student_t,age);
printf("sptr=%p\n",sptr);
sptr = container_of(&stu.name,Student_t,name);
printf("sptr=%p\n",sptr);
sptr = container_of(&stu.id,Student_t,id);
printf("sptr=%p\n",sptr);
printf("age:%p name:%p id:%p size:%ld\n", \
&stu.age,&stu.name,&stu.id,sizeof(stu));
return 0;
}
运行结果如下:
ptr=0x7ffca8831e50
sptr=0x7ffca8831e50
sptr=0x7ffca8831e50
age:0x7ffca8831e50 name:0x7ffca8831e54 id:0x7ffca8831ed4 size:136
可以看出container_of宏,可以完美的通过结构体变量指针和结构体类型的到结构体的首地址。
原文链接: