[英]Pointer casting problem with struct array member
我已經在舊版代碼庫中遇到了這個問題,但我真的不知道為什么它的行為方式完全正確。
在下面的代碼中, 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;
關鍵是代碼“ 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 */
}
這是一件很討厭的事情(編譯出來的事情)。 您基本上是在嘗試破解代碼,而不是使用消息中的數據副本(為其提供的8000個字節),而是嘗試放置一個指針,並將其傳遞給IPC。
主要問題是在進程之間共享內存。 發送該指針后,誰知道該指針發生了什么? 誰知道指向的數據會發生什么? 發送一個指向不受您控制的數據的指針(即:不受保護/正確共享)是非常糟糕的習慣。
對齊可能會發生的另一件事,也可能是您實際上正在談論的問題。 該數組是char
的數組,結構中的前一個成員很short
,編譯器可能會嘗試打包它們。 將char[]
重鑄為int *
意味着您無需告知編譯器即可占用內存區域並將其表示為其他內容。 您在演員uLen
踩踏uLen
。
memcopy
是執行此操作的正確方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.