参考:
http://blog.csdn.net/yinkaizhong/article/details/4093795
http://www.cnblogs.com/sdphome/archive/2011/09/14/2176624.html
container_of的函数实现:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) /** * 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)); })
如下图所示:
定义一个结构体struct student结构体,初始化一个stu,container_of的作用是,知道stu中一个成员的地址,算出stu这个结构体的地址。如知道stu->sex的地址,返回stu的地址
分三步完成:
(1)得到结构体成员 物理地址 如得到:sut->sex
const typeof(((type *)0)->member)*__mptr = (ptr);
(2)得到成员在结构体中的偏移量 ,如上图得到 在sturct student中,成员sex的 偏移量为 20
offsetof(type,member)
(3)得到stu的 物理地址 ,如上图得到 sut = stu->sex - 20 ,这样就完成了返回stu物理地址。
(type *)( (char *)__mptr - offsetof(type,member) )
下面看一个实例程序:
#include<stdio.h> struct student{ char name[20]; char sex; int num; }stu= {"mingming",'m',101}; main() { struct student *stu_ptr; int offset; const typeof(((struct student*)0)->sex) *_mptr = &stu.sex;//(1)得到成员_mptr= stu->sex的物理地址 printf("_mptr= 0x%d\n",_mptr); offset = (int)(&((struct student *)0)->sex);//(2)成员在结构体中绝对偏移量 printf("offset = %d\n",offset); stu_ptr = (struct student *)((char*)_mptr - offset);//(3)得到结构体stu 的物理地址 printf("stu_ptr = 0x%d\n",stu_ptr); printf("stu_ptr->name:%s\tstu_ptr->sex:%c\n", stu_ptr->name, stu_ptr->sex); return 0; }container_of可以分解为上面程序中的三步完成:
(1)得到成员_mptr= stu->sex的物理地址
首先定义一个 _mptr指针, 类型为struct student结构体中sex成员的类型,typeof 为获取(((struct student*)0)->sex)的类型,此处此类型为char,((struct student*)0)在offsetof处讲解
(2)成员在结构体中绝对偏移量
((struct student*)0)为 把 0地址 强制转化为指向student结构体类型的指针,该指针从地址 0 开始的 21个字节用来存放name 与 sex(char name〔20〕与 char sex共21字节),sex存放在第20个字节出(从0字节开始),&((struct student *)0)->sex 取出sex地址(此处即为20) 并强制转化为整形,所以offset为20,后面的printf结果将证明这一点
(3)得到结构体stu 的物理地址
((char*)_mptr - offset)此处先把_mptr指针转化为字符形指针,(为什么这么做呢? 如果_mptr为整形指针 _mptr - offset 相当于减去 sizeof(int)*offset个字节),减去 offset值 相当于 得到_mptr所在结构体的首地址(即stu的地址),然后我们把 该地址 强制转化为 struct student类型即可正常使用了
上面程序运行结果为:
root@android-virtual-machine:/uniteq_smb/test# ./teset_conta _mptr= 0x134520872 offset = 20 stu_ptr = 0x134520852 stu_ptr->name:mingming stu_ptr->sex:m