有如下结构体:

1
2
3
4
5
6
7
8
struct Test {
int a;
// ....
// 还有若干成员
// ...
int y;
int z;
};

在只知道成员变量y地址的情况下,如何获取到结构体的首地址?

可以通过如下宏来实现:

1
2
3
#define GET_PARENT_ADDRESS(address, type, field) ((type *)( \
(char*)(address) - \
(ULONG_PTR)(&((type *)0)->field)))

使用方法如下:

1
2
3
4
5
6
7
8
9
int main()
{
Test t = { 1, 2, 3 };

Test* pT = GET_PARENT_ADDRESS(&t.b, Test, b);
printf("a:%d b:%d c:%d\n", pT->a, pT->b, pT->c); // 输出a: 1 b:2 c:3

return 0;
}

核心原理:

通过将空指针强转成 Test* 类型, 然后再取成员变量b的地址,该操作的作用是:假设 Test 开始在 0x00000000 内存位置上分配内存,并在此基础上得b的内存地址,这样等同于获得了成员 b 的结构体对齐后偏移量。

最后,用 b 的实际内存地址减去b的偏移量就是结构体的首地址。

参考:Microsoft 完成端口CONTAINING_RECORD宏的实现。

本文最初发布在我的CSDN博客:《CONTAINING_RECORD宏的实现原理》,在此基础上稍作整理。


限于政策原因,在您看到该文章时,博客可能已经关闭了评论功能🥺

您可以通过在 blog-comment 项目中提交Issue来间接地发表评论🍀