簡體   English   中英

結構數組成員的指針轉換問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM