原文地址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就直接訪問該對象的成員