offsetof宏与container_of宏
offsetof宏的作用
用宏来计算结构体中某个元素和结构体首地址的偏移量(其实质是通过编译器来帮我们计算)。
container_of宏的作用
知道一个结构体中某个元素的指针,反推这个结构体变量的指针。有了container_of宏,我们可以从一个元素的指针得到整个结构体变量的指针,继而得到结构体中其他元素的指针。
offsetof宏的原理
我们虚拟一个type类型结构体变量,然后用type.member的方式来访问那个member元素,继而得到member相对于整个变量首地址的偏移量。
container_of宏的原理
先用typeof得到member元素的类型定义成一个指针,然后用这个指针减去该元素相对于整个结构体变量的偏移量(偏移量用offsetof宏得到的),减去之后得到的就是整个结构体变量的首地址了,再把这个地址强制类型转换为type *即可。
offsetof宏的分析
offsetof宏原型
TYPE为结构体类型 ;MEMBER为结构体中一个元素的元素名
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
(TYPE *)0 这是一个强制类型转换,把0地址强制类型转换成一个指针,这个指针指向一个TYPE类型的结构体变量。
((TYPE *)0)->MEMBER (TYPE *)0是一个TYPE类型结构体变量的指针,通过指针指针来访问这个结构体变量的member元素
&((TYPE *)0)->MEMBER 等效于&(((TYPE *)0)->MEMBER),意义就是得到member元素的地址。但是因为整个结构体变量的首地址是0,所以&(((TYPE *)0)->MEMBER)取出来的地址即为MEMBER的地址偏移量。
container_of宏的分析
container_of宏原型
ptr为指向结构体元素的指针;
type为结构体类型;
member为结构体中一个元素的元素名
这个宏返回的是指向整个结构体的指针,类型为(type*)
#define container_of(ptr, type, member) ({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})
宏原型分析:
首先我们来看((type *)0)->member将0强制转换为type结构体类型的地址,然后从这个地址取出的member成员变量,得到member成员变量后使用typeof()就可以得到变量的类型也就是typeof( ((type *)0)->member )这一步,前面加的const是为了修饰使用typeof( ((type )0)->member )类型定义的指针变量__mptr不能去访问它,然后将传入指向member的成员的ptr指针赋值给_mptr,得到了指向member结构体成员变量的指针再减去有offsetof宏获得的成员变量在结构体中的偏移量,就可以得到结构体的起始地址,即为(type)型的结构体地址。