container_of()宏定义的执行,可以通过结构体成员的地址而得到结构体的首地址,它需要三个参数,第一个参数是一个结构体成员的地址,第二个参数是结构体类型,第三个参数是结构体的成员,其推算的总思路是,获得一个结构体成员的地址,和这个结构体成员相对于首地址的偏移,然后使用结构体成员的地址,减去成员对首地址的偏移,即可得到结构体的首地址。
如此,需要解决两个问题,一是如何得到一个结构体成员的地址,二是如何算出这个成员相对于首地址的偏移。
对于第二个问题,使用了0地址,先把0地址强制转换成指定的结构体类型,即0地址是指定的结构体类型,那么相对于0地址的成员地址就是相对于0地址的偏移地址,因此可以得到成员偏移的长度。offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)就是实现这个功能的宏定义。
对于第一个问题,首先要确定这个结构体成员的类型,采用typeof(结构体成员)的方式获得,然后使用获得的结构体成员的类型定义一个指针,让这个指针指向这个成员的地址,即可获得这个成员的地址,即相当于对这个结构体成员执行了取地址的操作,即typeof( ((type *)0)->member ) *__mptr = (ptr); 的含义。
当这两个条件都达到了,就可以通过相减而获得了结构体的首地址了。
其中,typeof()关键字是获得一个变量的类型,返回这个变量的类型,比如
unsigned int i;
typeof(i) x;
x=100;
printf("x:%d ",x);
那么x是i的类型,而i是unsigned int型,因此x也是unsigned int类型。
#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) );})
struct test{
char buf[5];
int i;
int j;
};
int main()
{
struct example *tmp=malloc(sizeof(struct test));
printf("%p\n",tmp);
printf("%p\n",&(tmp->i));
printf("%p\n",(void *)offsetof(struct test,i));
printf("%p\n",container_of(&(tmp->i),struct test,i));
return 0;
}
来源:https://www.cnblogs.com/image-eye/archive/2011/07/17/2108589.html