经常我们在一些开源的或者内核代码中会看到。
#define TYPE_STRUCT(ptr, type, member)((type *)((char*)(ptr)-(unsigned long)(&((type *)0)->member)))
就是由结构体的成员地址获得结构体的地址。
参数:
ptr :结构体的某个成员地址。
type:结构体名
member:该成员名
这个就是很巧妙地利用了已知结构体的地址情况下用
struct_ptr -> member
利用"->"求成员的地址,其实就是
结构体首地址+偏移量
来求得成员地址。
于是我们把0地址强制转换成该结构体的地址,再用"->"来求偏移量:
(unsigned long)(&((type *)0)->member))
那么反过来用成员地址 “回退” 这个偏移量就得到了结构体 变量的首地址了。
((type *)((char*)(ptr)-(unsigned long)(&((type *)0)->member)))
那么整个过程其实就是
结构体首地址=成员地址-该成员在该结构体里的偏移量
注意:
注意其中的
((type *)((char*)(ptr)
它是首强制转换成了 char* 。
其实道理大家都懂,就是强制转换了在进行指针的 加 减 运行 就是按 “字节”来的。