C++小技巧 —— CONTAINING_RECORD [转]

原文地址https://www.cnblogs.com/Crazycatmiao/p/6731477.html

CONTAINING_RECORD

Containing record是一个在C++编程中用处很大的一种技巧,它的功能为已知结构体或类的某一成员对象中该成员的地址以及这一结构体名或类名,从而获得该对象的基地址html

因为写法简单,它被当作一个宏来使用,写法是这样的。编程

#define CONTAINING_RECORD(address,type,field) \ ((type*)((PCHAR)(address)-(ULONG_PTR)(&((type*)0)->field)))

这个宏运用的是地址的偏移来实现的,这里咱们须要补充一个知识点:spa

用type*来对0进行强制类型转换(type是一个结构体名或类名)再调用其成员后,该成员的地址就等于其相对于基地址的相对地址即偏移。指针

typedef struct {        //相对地址 
    int m_1;            //0x0
    int m_2;            //0x4
    int m_3;            //0x8
}DATA,*PDATA; int main() { int* v3 = (int*)(&((PDATA)0)->m_2); printf("%p\r\n",v3); //最后输出结果为4,即m_2的相对地址。
  }

明白了这个就更容易理解CONTAINING_RECORD的实现了,显然,该对象的绝对地址,就等于对象中某一个成员的绝对地址减去这一成员的相对地址。而刚刚咱们计算的就是这一相对地址。code

(ULONG_PTR)(&((type*)0)->field))(PCHAR)(address) 则是该成员的绝对地址,最后两个相减,就获得了对象的基地址,利用这个基地址能够作不少事情。htm

注意取地址以后的强制类型转换对象

最终的实现:blog

typedef struct {        //相对地址 
    int m_1;            //0x0
    int m_2;            //0x4
    int m_3;            //0x8
}DATA,*PDATA; // 利用地址的偏移和对0用结构体指针型强制类型转换来实现对结构体基地址的寻址。 //三参数:某一成员、对象中该成员的地址以及这一结构体名或类名
#define CONTAINING_RECORD(address,type,field) ((type*)((PCHAR)(address)-(ULONG_PTR)(&((type*)0)->field)))
int main() { DATA Data = {33,22,11}; //int* v3 = (int*)(&((PDATA)0)->m_1);
    int* v1 = &Data.m_2; PDATA v2 = CONTAINING_RECORD(v1, DATA, m_2); printf("%d %d %d\n", v2->m_1,v2->m_2,v2->m_3); //printf("%p\r\n", v3);
    return 0; } //最终v2就是对象Data的地址,咱们能够不使用Data就直接访问该对象的成员
相关文章
相关标签/搜索