当前位置 : 主页 > 编程语言 > c语言 >

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

来源:互联网 收集:自由互联 发布时间:2023-09-07
今天在项目中需要使用到结构体数据成员的偏移量计算,可以使用下面的方法来进行巧妙的获取,注意区别数据成员的赋值操作哦; # 1. 结构体指针为0时,数据成员赋值会内存访问崩溃

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

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

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

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

- 源代码:


```cpp


#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;

}



```


- 输出结果:

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



# 3. 原理解释:

- 在结构体成员变量前面加上取地址符号&后表示取的是`nAddrWidth`字段的地址,而不是引用该字段内容,因此不会产生段错误。

- 如果`ptr`为空,直接取该成员变量的内容或者更新、设置该内存的值时会发生段错误。

网友评论