container_of,typeof详解

来源:互联网 发布:python封装成dll 编辑:程序博客网 时间:2024/05/14 12:49
  1. 1.源码
  2. /**
  3.  * container_of - 通过结构体的一个成员获取容器结构体的指针
  4.  * @ptr: 指向成员的指针。
  5.  * @type: 成员所嵌入的容器结构体类型。
  6.  * @member: 结构体中的成员名。
  7.  *
  8.  */
  9. #define container_of(ptr, type, member) ({ \
  10.     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  11.    (type *)( (char *)__mptr - offsetof(type,member) );})
  12.  这个宏的作用,就是通过一个容器(结构体)中某个成员的指针得到指向这个容器(结构体)的指针,简单的说就是通过成员  找容器。
  13. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)


  14. 2.用法
  15. 例如:

    typedef struct frame {
            int a;
            char b;
            char name[10];
    } frame_t;


    int main(int argc, char **argv)
    {
            frame_t fra, *pf;
            fra.a = 1;
            fra.b = 2;
            snprintf(fra.name, 5, "cjz%d", 1);


            pf = container_of(&fra.a, frame_t, a);
            printf("fra.a = %d, fra.b = %d, fra.name = %s\n", fra.a, fra.b, fra.name);


            return 0;
    }

    参考:http://blog.csdn.net/cuijianzhongswust/article/details/8249352
  16. 3.详解

  17. 先分析一下这个 宏的运行机理:

  18. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    一共4步 
    1. ( (TYPE *)0 ) 将零转型为TYPE类型指针; 
    2. ((TYPE *)0)->MEMBER 访问结构中的数据成员; 
    3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址; 
    4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型。巧妙之处在于将0转 换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址;

  19. 注释:

    1.要将地址赋给指针, int *p = 0x12345678是不对的 。正确的方式应为:int *p = (int *) 0x12345678。在大多数计算机中,内存地址确实是以无符号整型数来表示的,而且多以16进制表示,但我们在C语言中不能用整型数去表示地址,只能用指针常量来表示,因为它是被用来赋给一个指针的。

    对于这个赋值问题还可以换一个角度去理解,在C语言中,使用赋值操作符时,赋值操作符左边和右边的表达式类型应该是相同的,如果不是,赋值操作符将试图把右边表达式的值转换为左边的类型。所以如果写出int *p = 0x12345678 ; 这条语句编译器会报错:'=' : cannot convert from ' const int ' to ' int * ' ,因为赋值操作符左边和右边的表达式的类型应该相同,而0x12345678是int型常量,p是一个指向int型的指针,两者类型不同,所以正确的方式是:int *p = (int *) 0x12345678 ; 

  20. 故((TYPE*)0)是将地址为0转换成TYPE*型指针。即地址0处存放指向TYPE类型数据的地址。则((TYPE*)0)->MEMBER指向TYPE类型数据的成员MEMBER.((TYPE*)0)->MEMBER相当于(*((TYPE*)0)).MEMBER.

  21.  

  22. 参考:http://blog.chinaunix.net/uid-28458801-id-4200573.html

  23. (1)const typeof( ((type *)0)->member ) *__mptr = (ptr);                                          typeof即将参数*_mptr定义为((type *)0)->member类型,即复制ptr。
    定义一个中间变量__mptr,它等于提供给宏的参数ptr,也就是指向某个成员的指针。这个中间变量的命名意义是:
    "__"代表内部使用,内核编程中常常这么做;
    “m”代表middle。
    1.     为了避免对 ptr及prt指向的内容造成破坏,这里不直接使用 ptr 而要多多加一个__mptr。
    (2)(type *)( (char *)__mptr - offsetof(type,member) );
    这行代码的作用是通过中间变量__mptr(指向某个成员的指针)减去这个成员在容器(结构体)中的偏移来得到指向容   器(结构体)的指针。 把__mptr转换成 char *类型,因为offsetof得到的偏移量是以字节为单位。两者相减得到结构体的起始位置,再强制转      换成type类型。

    参考:http://blog.chinaunix.net/uid-20543672-id-3205315.html



0 0
原创粉丝点击