zoukankan      html  css  js  c++  java
  • C++小技巧之CONTAINING_RECORD

    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
    ",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
    ", v2->m_1,v2->m_2,v2->m_3);
    	//printf("%p
    ", v3);
        return 0;
    }
    //最终v2就是对象Data的地址,我们可以不使用Data就直接访问该对象的成员
    
  • 相关阅读:
    [SAP Rolling Out] Unit TEST/INTEGRATION TEST/UAT TEST/PARREL TESTING
    针式PKM与众不同的地方
    针式PKM拖动收集功能兼容所有的浏览器
    周九常:个人知识管理的三个重点领域
    关闭word文件老是说normal.dot被另外一人使用
    针式PKM初级应用:修改知识点的颜色评介
    寻找识货的人
    针式PKM中级应用如何将知识管理应用到新项目研发中
    针式PKM中级应用在10秒以内找到本月收集的任意文章
    针式PKM中级应用:知识点之间如何链接
  • 原文地址:https://www.cnblogs.com/Crazycatmiao/p/6731477.html
Copyright © 2011-2022 走看看