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


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

CONTAINING_RECORD

Containing record是一個在C++編程中用處很大的一種技巧,它的功能為已知結構體或類的某一成員對象中該成員的地址以及這一結構體名或類名,從而得到該對象的基地址

由於寫法簡單,它被當做一個宏來使用,寫法是這樣的。

#define CONTAINING_RECORD(address,type,field) \

((type*)((PCHAR)(address)-(ULONG_PTR)(&((type*)0)->field)))

這個宏運用的是地址的偏移來實現的,這里我們需要補充一個知識點:

用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的實現了,顯然,該對象的絕對地址,就等於對象中某一個成員的絕對地址減去這一成員的相對地址。而剛剛我們計算的就是這一相對地址。

(ULONG_PTR)(&((type*)0)->field))(PCHAR)(address) 則是該成員的絕對地址,最后兩個相減,就得到了對象的基地址,利用這個基地址可以做很多事情。

注意取地址之后的強制類型轉換

最終的實現:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM