#include
#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)
/*
ptr是指向结构体成员的指针
type是结构体的类型,例如struct abc
member是成员的变量名
*/
/*
1、typeof( ((type *)0)->member ):取得成员的类型
2、const typeof( ((type *)0)->member ) *__mptr = (ptr); :定义指向成员类型的指针变量__mptr,并将第一个参数(指向成员的指针)赋值给__mptr
3、offsetof(type,member) : 计算结构体中成员变量相对于结构体指针的偏移量
4、(TYPE *)0)->MEMBER:起始地址为0的结构体中成员变量的地址,也就是成员的偏移值
PS:这个实现最巧妙的地方在于“(type *)0”的应用,将地址0强行转换成指向某个类型的指针
*/
struct student{
char name[20];
char sex;
}stu = {"xiaobo",'m'};
int main()
{
struct sudent *ptr;
ptr = (struct student *)0;
printf("stu的起始地址:%p/n",&stu);
printf("stu.sex的起始地址:%p/n",&(stu.sex));
printf("stu.sex的起始地址:%p/n",ptr);
//printf("stu.sex的起始地址:%p/n",(*ptr)->sex);
struct student *stu_ptr;
int offset;
/*
const typeof( ((type *)0)->member ) *__mptr = (ptr);
首先定义一个 _mptr指针, 类型为struct student结构体中sex成员的类型
typeof 为获取(((struct student*)0)->sex)的类型,此处此类型为char
*/
const typeof(((struct student *)0)->sex) *_mptr = &stu.sex;
/*
((struct student*)0)为 把 0地址 强制转化为指向student结构体类型的指针
该指针从地址 0 开始的 21个字节用来存放name 与 sex(char name〔20〕与 char sex共21字节)
sex存放在第20个字节出(从0字节开始)
&((struct student *)0)->sex 取出sex地址(此处即为20) 并强制转化为整形从而得出sex相对于0
的偏移量
*/
offset = (int)&(((struct student *)0)->sex);//偏移量
stu_ptr = (struct student *)((char*)_mptr - offset);
printf("offsetof stu.sex = %d/n",offset);
printf("stu_ptr->name:%s/tstu_ptr->sex:%c/n",stu_ptr->name,stu_ptr->sex);
/*利用linux 中的宏定义*/
struct student *stu_ptr2;
stu_ptr2 = container_of(&stu.sex,struct student,sex);
printf("stu_ptr2->name:%s/tstu_ptr2->sex:%c/n",stu_ptr2->name,stu_ptr2->sex);
return 0;
}
/*
输出结果:
stu的起始地址:0x804a014
stu.sex的起始地址:0x804a028
stu.sex的起始地址:(nil)
offsetof stu.sex = 20
stu_ptr->name:xiaobostu_ptr->sex:m
stu_ptr2->name:xiaobostu_ptr2->sex:m
巧妙之处是利用(type *)0,将地址0强行转换成指向某个类型的指针,并利用其中某个成员的地址,计算出其相对于0的偏移量从而得出该结构体的指针 即其地址
下面再给出这个巧妙之处的一个例子。
*/