1、 功能
Container_of是从一个已知的结构体和其中一个成员及其该成员的指针,返回该结构体的首地址。字面意思:装某某成员的容器的地址。
2、 原型(在linux/kernel.h中定义)
#definecontainer_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member )*__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
ptr就是成员的指针,type是结构体类型,member是结构体成员。其中的offsetof又是一个宏定义,在linux/stddef.h中定义:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
offsetof(offset偏移量,意思某某成员在该结构体的偏移量)是为了求结构体中某个成员相对于结构体首地址的偏移量,但现在不知道其首地址,所以用了一个技巧,相当于把结构体移到地址0,这样取出该成员的地址就是相对于结构体首地址的偏移量。这儿有一个注意点,就是在0地址取结构体的成员的地址,这是允许的,因为我们没有取该地址里的值,而是取该地址。(事实上,此处并没有值,所以取值会出现段错误)。另外__mptr指针需转换成char*型,因为指针减去一个数相当于减去该指针类型的那么多个偏移量。
3、 代码验证如下:
#include <stdio.h>
#include <stddef.h>
struct stu{
char name[20];
int age;
float score;
};
int main(void)
{
struct stu xiaoyuan = {"xiaoyuan", 32, 56.4};
printf("offset of age is [%d]\n", offsetof(struct stu, age));
printf("offset of score is [%d]\n", offsetof(struct stu, score));
printf("%d\n", (size_t)((int)&xiaoyuan.age - (int)&xiaoyuan));
printf("%d\n", (size_t)&(((struct stu*)0)->age) );
/* 相当于
* printf("%d\n", (size_t)(&(((struct stu*)0)->age)- 0) );
*/
return 0;
}
运行结果:
[root@localhost~]# ./a.out
offset of age is[20]
offset of scoreis [24]
20
20