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 函数,效果也是一样的