struct array成员的指针转换问题

时间:2011-02-16 08:45:12

标签: c pointers casting arm

我在遗留代码库中遇到过这个来源,我真的不知道它为什么会像它那样行事。

在以下代码中,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
}

3 个答案:

答案 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 */ 
}