前言:网上对这些宏的解释特别多,有些博客也写得特别精彩,不过为了加深理解,特地写一下分析过程。
offsetof
1、宏定义如下
/*
* 宏包含两个参数:
* --type 结构体类型
* --member 结构体成员变量名
*/
#define offsetof(type, member) ( (size_t)&(((type *)0)->member) )
2、作用:返回结构体type中member成员相对于结构体首地址的偏移量,以字节为单位。
3、解释:这个宏的精髓在于将0强制类型转换为type类型的指针,对编译器来说,存在一个首地址为0x00000000,类型为type的结构体。
4、分析分三步:
① ((type *)0)->member,存在一个起始地址为0x00000000,类型为type的结构体,它的成员变量member的值。
②&(((type *)0)->member),取结构体成员变量member的地址,并且对这个地址是相对0进行偏移的。
③(size_t)&(((type *)0)->member),对偏移值进行size_t类型转换。
container_of
1、宏定义如下
/*
* 宏包含三个参数
* --ptr 指向结构体成员变量member的指针
* --type 结构体类型
* --member 结构体成员变量名
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char*)__mptr - offsetof(type, member) ); \
})
2、作用:根据一个结构体变量中成员变量的指针来获取指向整个结构体变量的指针。
3、解释:整个宏可以拆开成两部分
1> const typeof( ((type *)0)->member ) *__mptr = (ptr);
① typeof是用来获取成员变量member的数据类型。
②通过typeof定义一个member指针类型的临时变量__mptr。
③将__mptr变量指向memberodga的指针变量ptr,这相当于创建了一个临时变量,防止后续操作改变了ptr。
2>(type *)( (char*)__mptr - offsetof(type, member) );
① (char*)__mptr,将指针变量类型转换成char*,offsetof(type, member)是结构体type中member成员变量相当于结构体首地址的偏移量。
②(char*)__mptr - offsetof(type, member),用member的实际地址减去偏移量,得到type的起始地址。
③将这个地址进行(type*)转换,得到了指向type类型的指针。
list_entry
#define list_entry(ptr, type, member) container_of(ptr, type, member)
待补充。。。
list_for_each_entry
/*
* 宏包含三个参数
* --pos
* --head
* --member
*/
#define list_for_each_entry(ptr, head, member) ({ \
for (pos = list_entry((head)->next, typeof(*pos), (member)); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), (member)) )
})
待补充