#include<stdio.h> #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:xiaobo stu_ptr->sex:m stu_ptr2->name:xiaobo stu_ptr2->sex:m 巧妙之处是利用(type *)0,将地址0强行转换成指向某个类型的指针,并利用其中某个成员的地址,计算出其相对于0的偏移量从而得出该结构体的指针 即其地址 下面再给出这个巧妙之处的一个例子。 */ #include"stdio.h" struct student{ int number; char name[10]; char sex; }xiaobo={1000,"xiaobo",'m'}; void main() { struct student *stu_ptr; //假设现在只知道xiaobo.sex的地址想要得到xiaobo的地址 //sex 相对于0的偏移量 int offset = (int *)&(((struct student *)0)->sex);//得偏移量 知道其地址可得结构体的起始地址 printf("%d/n",offset); //现在知道name的地址 int offset2 = (int *)&(((struct student *)0)->name); } /* 输出结果 14 10 综上用(type * )0即结构体类型的aobo的"