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

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

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

在这里插入图片描述

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为空,直接取该成员变量的内容或者更新、设置该内存的值时会发生段错误。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值