container_of宏解析

1.首先贴源码,如下

#define container_of(ptr, type, member) ({            \
    const typeof(((type *)0)->member) * __mptr = (ptr);    \
    (type *)((char *)__mptr - offsetof(type, member)); })

  传入参数解析:

    ptr:结构体成员变量的起始地址

    type:结构体类型

    member:结构体成员变量的名称    

 

  官方api解释:

    container_of宏的作用是通过结构体内某个成员变量的地址和该变量名,以及结构体类型。找到该结构体变量的地址。这里使用的是一个利用编译器技术的小技巧,即先求得结构成员在结构中的偏移量,然后根据成员变量的地址反过来得出主结构变量的地址。

2.解析:

const typeof(((type *)0)->member) * __mptr = (ptr);

  1、(type *) 0

    把0地址强转成type类型,也就是传入的结构体类型

  2、 typeof(((type *)0)->member)

    取结构体成员变量的 类型

    注:typeof,可以百度下这个函数的意义,官方解释就是取某个变量的类型,如int a; typeof(a) 就为int

  3、 typeof(((type *)0)->member) * __mptr = (ptr);

    把结构体成员变量的起始地址赋值给__mptr

  4、offsetof(type, member) , 原型如下

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

    官方解释是: 取某个结构体成员结构体本身起始地址的偏移大小

 

    (TYPE* 0),先把 0 地址强转成type类型,也就是传入的结构体类型 

    其次仔细看 & 取地址符,取的是TYPE类型结构体的MEMBER 变量的地址

    其次再仔细想想,取 0 地址的MEMBER 变量的地址,那么就直接得到该MEMBER变量与0地址的偏移大小了

    也就与官方解释对应上了

 

  5.(char *)__mptr - offsetof(type, member))

    有了上面的解释,这里就好理解了,用结构体成员变量起始地址,减去算出来的偏移地址,就得到结构体本身的起始地址了

 

3.所以再一次确定传入的变量

    ptr:结构体成员变量的起始地址

    type:结构体类型

    member:结构体成员变量的名称

  

  所以在使用中往往list_for_each 与 list_entry 搭配使用,list_for_each 就是为了获得结构体成员变量的起始地址 

  或者直接使用list_for_each_entry 函数,效果也是一样的

 

参考连接:https://www.imooc.com/article/313395

posted @ 2021-03-29 10:18  辣椒炒牛肉  阅读(322)  评论(0编辑  收藏  举报