我在遗留代码库中遇到过这个来源,我真的不知道它为什么会像它那样行事。
在以下代码中,pData
struct成员要么包含数据,要么指向共享内存中的实际数据。使用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
}
答案 0 :(得分:3)
我怀疑这是一个对齐问题,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;
答案 1 :(得分:0)
这是一个非常讨厌的事情(编译出来的东西)。您正在尝试破解代码,而不是在消息中使用数据副本(在提供的8000字节中),您尝试放置一个指针,并将其传递给IPC。
主要问题是在进程之间共享内存。谁知道发送后该指针会发生什么?谁知道它指向的数据会发生什么?发送指向不受您控制的数据的指针(即:未受保护/正确共享)是一个非常糟糕的习惯。
可能发生的另一件事,可能是你实际谈论的,是对齐。该数组为char
,结构中的前一个成员为short
,编译器可能会尝试打包它们。将char[]
重新转换为int *
意味着您不需要告诉编译器就占用内存区域并将其表示为其他内容。你是由演员踩踏uLen
。
memcopy
是正确的方法。
答案 2 :(得分:0)
这里的重点是代码“int header =(((int )(txUserPtr) - 4))” UserTypes和struct指针转换的插图很有帮助!
typedef union UserTypes
{
SAUser AUser;
BUser BUser;
SCUser CUser;
SDUser DUser;
} UserTypes;
typedef struct AUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} AUser;
typedef struct AUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} AUser;
typedef struct BUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} BUser;
typedef struct CUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} CUser;
typedef struct DUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} DUser;
//this is the function I want to test
void Fun(UserTypes * txUserPtr)
{
int header = (*((int*)(txUserPtr) - 4));
//the problem is here
//how should i set incoming pointer "txUserPtr" so that
//Fun() would skip following lines.
// I don't want to execute error()
if((header & 0xFF000000) != (int)0xAA000000)
{
error("sth error\n");
}
/*the following is the rest */
}