Linux的c语言哲学之offsetof和container_of
文章目录
内核版本 | 作者 |
---|---|
Linux4.4 | nineyole |
offsetof
针对宏定义的详细说明
宏定义源码如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
offsetof宏定义的主要作用:获得结构体(TYPE)的变量成员(MEMBER)在此结构体中的偏移量。
( (TYPE *)0 )
上面代码是将0强制转换为一个类型为TYPE类型的指针,并且这个TYPE类型的指针的地址是0。
((TYPE *)0)->MEMBER
上面代码是访问结构TYPE中的的MEMBER数据成员。
&( ( (TYPE *)0 )->MEMBER )
上面代码是取出数据成员MEMBER的地址。并且由于TYPE的地址是0,因此获取到的地址就是相对成员MEMBER在结构体TYPE中的偏移。
(size_t)(&(((TYPE*)0)->MEMBER))
将得到偏移结果转换类型。对于32位系统而言,size_t是unsigned int类型;对于64位系统而言,size_t是unsigned long类型。
图解offsetof
相当于有一个结构体TYPE,求这个结构体中其中一个成员变量MEMBER在该结构体的中偏移位置。
注意事项:需要考虑在编译过程中的结构体对齐问题。
container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
针对宏定义的详细说明
主要作用:根据结构体(type)变量中的域成员变量(member)的指针(ptr)来获取指向整个结构体变量的指针。
代码解释:
第一行
typeof( ( (type *)0)->member )
表示取出结构体type变量的member成员的变量类型。
const typeof( ((type *)0)->member ) *__mptr = (ptr)
表示利用member的类型定义一个 __mptr指针,并且这个指针指向成员变量member所指向的地址。
第二行
(char *)__mptr
将__mptr指针强制类型转换成字节型指针。
offsetof(type,member))
这个前面讲过了,就是获取member成员在结构体type中的位置偏移。
(char *)__mptr - offsetof(type,member))
就是用成员变量的绝对地址减去member在结构体type中的偏移位置,就表示结构体type的指针的起始地址,这个时候还是为char *型指针。
(type *)( (char *)__mptr - offsetof(type,member) )
就是将char *指针类型的结构体type的指针(表示type的绝对地址)强制转换成type *类型的结构体type的指针。
图解container_of
相当于已知一个结构体type的成员member的地址,去获取这个结构体的地址。其实现原理就是通过offsetof获取member在type中的偏移地址,然后经过一系列类型转换获得的。