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就直接訪問該對象的成員
相關文章
相關標籤/搜索