container_of宏
1. 介绍
- 接口:container_of(ptr, type, member)
- ptr 表示结构体中的member的地址
- type 结构体类型
- member 结构体的某个成员
- 作用:从包含在某个结构体中的结构成员获取结构体本身的指针,也就是通过结构体变量中的某个成员的首地址获取结构体的首地址
2. 分析
a、原型
- container_of
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#ifndef container_of
- offsetof
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
b、分析
第一步:首先定义一个临时的数据类型与ptr相同的变量_mptr,用来保存ptr的值。
- typeof(((type *)0)->member)用来获取变量的类型
第二步:使用(char *)_mptr的值减去member在结构体偏移量,计算结果就是结构体变量的首地址。
- 指针的加减要注意类型,用(char*)ptr是为了计算字节偏移。
- ((type *)0)->member是一个小技巧。
c、实例:
/* 有结构体定义如下: */
typedef struct fuck {
......:
void member;
......:
}type;
/* 有类型如下: */
type a;
type *point;
void *ptr;
/* 执行: */
ptr = &(a.member);
point = list_entry(ptr, type, member);
先看 &((type )0)->member,把0强制转换为指针类型,则该指针一定指向”0”(数据段地址)。因为指针是”type “型的,所以可取到以”0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏字节数。
在看 (type ) (char )(ptr) - (unsigned long)(&((type )0)->member),(char )(ptr)使得指针的加减操作步长为一字节,(unsigned long)(&((type )0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者相减便得出该结构体的地址。转换为(type )类型即可,ok。