- 今天在项目中需要使用到结构体数据成员的偏移量计算,可以使用下面的方法来进行巧妙的获取,注意区别数据成员的赋值操作哦;
1. 结构体指针为0时,数据成员赋值会内存访问崩溃
![在这里插入图片描述](https://img-blog.csdnimg.cn/5dac9a56a98442c99180a63cda7501bb.png)
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;
int nHasS2Mm;
int nInitialized;
int nHasSg;
int nTxNumChannels;
int nRxNumChannels;
int nMicroDmaMode;
int nAddrWidth;
}stuXAxiDma;
#define VAROFFSET(type, mem) ((unsigned long)(&((type *)0)->mem))
#define GET_STRUCT_ENTRY(ptr, type, mem) ((type *)((char *)ptr - VAROFFSET(type, mem)))
typedef struct
{
int* pBdTxChainBuffer;
int* pBdRxChainBuffer;
int nDmaDevId;
int nS2mmIntrId;
int nMm2sIntrId;
int nBdCount;
char cBdNum;
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* pAudioChannel = GET_STRUCT_ENTRY(pCallBackRef, stuChipAudioChannel, axiDma);
printf("dmaInterruptHandler::pAudioChannel=[%p]\n", pAudioChannel);
}
int _tmain(int argc, _TCHAR* argv[])
{
stuXAxiDma* ptr = new stuXAxiDma();
ptr->nAddrWidth = 0;
int nAddrWidthOffset = (int)&(ptr->nAddrWidth);
int nBdTxChainBufferOffset = ((int)(&((stuChipAudioChannel*)0)->pBdTxChainBuffer));
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);
stuXAxiDma* pXAxiDma = new stuXAxiDma;
dmaInterruptHandler(pXAxiDma);
return 0;
}
- 输出结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/e78b7e79758e455b92b9d0cfa7bfa8e3.png)
3. 原理解释:
- 在结构体成员变量前面加上取地址符号&后表示取的是
nAddrWidth
字段的地址,而不是引用该字段内容,因此不会产生段错误。 - 如果
ptr
为空,直接取该成员变量的内容或者更新、设置该内存的值时会发生段错误。