c - 结构数组成员的指针转换问题

标签 c pointers casting arm

我在遗留代码库中遇到过这个源代码,但我真的不知道为什么它会以这种方式运行。

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

相关文章:

c - 如何引发浮点异常

c - 玩转信号

c - 帮助我理解这个函数标题。代码来自 FreeBSD 8 源代码 UFS 部分

C++ 字符串 : [] vs. *

oop - 使用 $cast 函数和任务在 SV 中进行动态转换

php - 如何从 Countable 对象中获取第一个元素?

swift - 挑战 Swift 中的类型转换

使用变量选择在点后打印多少个数字

c - 调用函数时如何使用指针

c - 浮点缓冲区转换为 unsigned char* 在套接字发送时丢失数据