【genius_platform软件平台开发】第八十五讲:如何获取结构体数据成员的偏移量(巧妙)

奋斗吧
奋斗吧
擅长邻域:未填写

标签: 【genius_platform软件平台开发】第八十五讲:如何获取结构体数据成员的偏移量(巧妙) Python博客 51CTO博客

2023-04-25 18:23:56 229浏览

【genius_platform软件平台开发】第八十五讲:如何获取结构体数据成员的偏移量(巧妙),今天在项目中需要使用到结构体数据成员的偏移量计算,可以使用下面的方法来进行巧妙的获取,注意区别数据成员的赋值操作哦;1.结构体指针为0时,数据成员赋值会内存访问崩溃2.结构体指针为0时,数据成员可以内存访问并计算偏移量源代码:#include"stdafx.h"#ifdefined(BUILD_AMBARELLA_AMBACV_DRV)&&defined(BUI


  • 今天在项目中需要使用到结构体数据成员的偏移量计算,可以使用下面的方法来进行巧妙的获取,注意区别数据成员的赋值操作哦;

1. 结构体指针为0时,数据成员赋值会内存访问崩溃

【genius_platform软件平台开发】第八十五讲:如何获取结构体数据成员的偏移量(巧妙)_c++

2. 结构体指针为0时,数据成员可以内存访问并计算偏移量

  • 源代码:
#include "stdafx.h"

#if defined (BUILD_AMBARELLA_AMBACV_DRV) && defined (BUILD_AMBARELLA_CAVALRY_DRV)
#error "Can not enable ambacv and cavalry at the same time"
#elif defined (BUILD_AMBARELLA_AMBACV_DRV)
#define CAVALRY_DEV_NODE	"/dev/ambacv"
#else
#define CAVALRY_DEV_NODE	"/dev/cavalry"
#endif


typedef struct 
{
    int nHasMm2S;		/* Has transmit channel */
    int nHasS2Mm;		/* Has receive channel */
    int nInitialized;	/* Driver has been initialized */
    int nHasSg;
    int nTxNumChannels;
    int nRxNumChannels;
    int nMicroDmaMode;
    int nAddrWidth;		  /**< Address Width */
}stuXAxiDma;

/*****************************************************************************/
/** 1.5 chip common part, audio interface, depend on DMA interface
******************************************************************************/
#define VAROFFSET(type, mem) ((unsigned long)(&((type *)0)->mem))
#define GET_STRUCT_ENTRY(ptr, type, mem) ((type *)((char *)ptr - VAROFFSET(type, mem)))
/*
 *callback function
 *Check interrupt status and assert s2mm flag
 */
typedef struct
{
    int* pBdTxChainBuffer;
    int* pBdRxChainBuffer;
    int nDmaDevId;
    int nS2mmIntrId;
    int nMm2sIntrId;
    int nBdCount;
    char cBdNum;                    // 注意未对齐32位系统占4个字节
    void(*s2mmFinishCb)(void*);
    void(*mm2sFinishCb)(void*);
    stuXAxiDma axiDma;
}stuChipAudioChannel;

static void dmaInterruptHandler(void* pCallBackRef)
{
    // 进行指针转换
    stuXAxiDma* pXAxiDmaPtr = (stuXAxiDma *)pCallBackRef;
    printf("dmaInterruptHandler::pCallBackRef=[%p]\n", pCallBackRef);

    //注意堆的特性,向上生长,地址变小
    //stuChipAudioChannel *p_audio_channel = (stuChipAudioChannel *)((char *)ptr - ((int)&((stuChipAudioChannel*)0)->axiDma));
    stuChipAudioChannel* pAudioChannel = GET_STRUCT_ENTRY(pCallBackRef, stuChipAudioChannel, axiDma);
    printf("dmaInterruptHandler::pAudioChannel=[%p]\n", pAudioChannel);
}


int _tmain(int argc, _TCHAR* argv[])
{
    // 申请内存给指针ptr赋值
    stuXAxiDma* ptr = new stuXAxiDma();
    //指针ptr设置为空((void*)0)
    //ptr = NULL;
    // 设置指针ptr的数据成员nAddrWidth = 0
    ptr->nAddrWidth = 0; // 内存访问会报错
    // 只是访问取数据成员变量没问题
    int nAddrWidthOffset = (int)&(ptr->nAddrWidth);
    // 能够直接取出偏移量来
    int nBdTxChainBufferOffset = ((int)(&((stuChipAudioChannel*)0)->pBdTxChainBuffer));
    // nBdTxChainBufferOffset=0
    printf("_tmain::nBdTxChainBufferOffset=[%d]\n", nBdTxChainBufferOffset);

    int nDmaDevIdOffset = ((int)(&((stuChipAudioChannel*)0)->nDmaDevId));
    printf("_tmain::nDmaDevIdOffset=[%d]\n", nDmaDevIdOffset);

    int nS2mmFinishCbOffset = ((int)(&((stuChipAudioChannel*)0)->s2mmFinishCb));
    printf("_tmain::nS2mmFinishCbOffset=[%d]\n", nS2mmFinishCbOffset);

    int nAxiDmaOffset = ((int)(&((stuChipAudioChannel*)0)->axiDma));
    printf("_tmain::nAxiDmaOffset=[%d]\n", nAxiDmaOffset);

    // 申请堆内存给pXAxiDma变量
    stuXAxiDma* pXAxiDma = new stuXAxiDma;
    dmaInterruptHandler(pXAxiDma);
    
	return 0;
}
  • 输出结果:

3. 原理解释:

  • 在结构体成员变量前面加上取地址符号&后表示取的是nAddrWidth字段的地址,而不是引用该字段内容,因此不会产生段错误。
  • 如果ptr为空,直接取该成员变量的内容或者更新、设置该内存的值时会发生段错误。




好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695