C语言的库函数中提供了计算结构体的一个元素在结构体中的偏移量,以及通过偏移量和结构体中元素的指针计算出来结构体的首地址。但是在一些场景没有办法使用C语言库中的函数,那么就需要自己进行定义。
如下面代码所示的两个宏定义就完成了计算结构体成员偏移地址,结构体成员首地址的功能。
/*@function: 计算出来“type”结构体类型中,field在结构体中的偏移量*@param type 结构体类型*@param field 结构体成员*@return 偏移量*/
#define offset_of(type, field) ((uint32_t)&(((type *)0)->field)
(1)上面宏中为什么使用“(type *)0”作为指针类型。
因为0作为基础地址,指向类型成员“field”的时候,这时候进行取址,得到的结果就是结构体成员“filed”的结构体内偏移地址。
(2)使用“(type *)0”最为指针,会不会导致内存泄露?
答案是不会,因为编译器只关心类型,只要不存在访问非法地址的内容就不会出现问题,那也是程序运行时的事情,而非编译时的事情;
也就是我们经常说的访问野指针,空指针,但是上述语句显然没有对指针指向的内存进行访问。
/*@function: 计算出来“ptr”所指向的“type”结构体类型中,指针减去field位置所在的偏移量,从而计算出来结构体的首地址指针*@param ptr 指向结构体成员地址的指针*@param type 结构体类型*@param field 结构体成员*@return 结构体的首地址指针*/
#define container_of(ptr, type, field) ((type *)((uint32_t)ptr - offset_of(type, field)))