图示/白话 container_of处理流程

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;
}

posted on 2011-07-17 22:36  image eye  阅读(649)  评论(0编辑  收藏  举报