我在遗留代码库中遇到过这个源代码,但我真的不知道为什么它会以这种方式运行。
在以下代码中,pData
结构成员包含数据或指向共享内存中实际数据的指针。使用 IPC(msgsnd()
和 msgrcv()
)发送消息。使用指针转换(当前已注释掉),在 ARM 目标上使用 GCC 4.4.1 失败,成员 uLen
被修改。使用 memcpy()
时,一切都按预期工作。我真的看不出指针转换有什么问题。这里有什么问题?
typedef struct {
long mtype;
unsigned short uRespQueue;
unsigned short uID;
unsigned short uLen;
unsigned char pData[8000];
} message_t;
// changing the pointer in the struct
{
unsigned char *pData = <some_pointer>;
#if 0
*((unsigned int *)pMessage->pData) = (unsigned int)pData;
#else
memcpy(pMessage->pData, &pData, sizeof(unsigned int));
#endif
}
// getting the pointer out
{
#if 0
unsigned char *pData; (unsigned char *)(*((unsigned int *)pMessage->pData));
#else
unsigned char *pData;
memcpy(&pData, pMessage->pData, sizeof(int));
#endif
}
最佳答案
我怀疑这是一个对齐问题,GCC 或处理器正在尝试进行补偿。结构定义为:
typedef struct {
long mtype;
unsigned short uRespQueue;
unsigned short uID;
unsigned short uLen;
unsigned char pData[8000];
} message_t;
假设正常的对齐限制和 32 位处理器,每个字段的偏移量是:
mtype 0 (alignment 4)
uRespQueue 4 (alignment 2)
uID 6 (alignment 2)
uLen 8 (alignment 2)
pData 10 (alignment 1)
除了最新版本的 ARM 处理器,内存访问必须在 ARM 处理器上对齐并与转换对齐:
*((unsigned int *)pMessage->pData) = (unsigned int)pData;
您正试图在未对齐的地址上写入 32 位值。为了更正对齐,地址似乎已截断地址的 LSB 以具有正确的对齐。这样做恰好与导致问题的 uLen
字段重叠。
为了能够正确处理这个问题,您需要确保将值写入正确对齐的地址。要么偏移指针以对齐它,要么确保 pData
对齐以便能够处理 32 位数据。我会重新定义结构以对齐 pData
成员以进行 32 位访问。
typedef struct {
long mtype;
unsigned short uRespQueue;
unsigned short uID;
unsigned short uLen;
union { /* this will add 2-bytes of padding */
unsigned char *pData;
unsigned char rgData[8000];
};
} message_t;
由于 mtype
字段,该结构仍应占用相同数量的字节,因为它具有 4 字节对齐。
那么你应该能够访问指针:
unsigned char *pData = ...;
/* setting the pointer */
pMessage->pData = pData;
/* getting the pointer */
pData = pMessage->pData;
关于c - 结构数组成员的指针转换问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5014268/