1

前几天,我的一个朋友在 Facebook 上发布了这个问题,而对于我的生活,我无法弄清楚。他正在使用 cubesat 协议编写客户端和服务器。由于某种原因,当他将协议结构的数据成员转换为指针时,他的数据似乎被破坏了。

客户端代码片段:

uint32_t data[3] = { 1234U, 5678U, 9101U };
memcpy(packet->data32, data, sizeof(data));
packet->length = sizeof(data);
csp_send(connection, packet, 1000);

服务器代码片段:

uint32_t *data = (uint32_t *)(packet->data32);
printf("Packet received on %i: %u\r\n", PORT, data[0]);
printf("Packet received on %i: %u\r\n", PORT, data[1]);
printf("Packet received on %i: %u\r\n", PORT, data[2]);
printf("Packet received on %i: %u, %u, %u\r\n", PORT, data[0], data[1], data[2]);

输出此代码产生:

Packet received on 15: 2182284498
Packet received on 15: 5678
Packet received on 15: 9101
Packet received on 15: 80904723, 372113408, 596443136

输出此代码的普通读者会期望:

Packet received on 15: 1234
Packet received on 15: 5678
Packet received on 15: 9101
Packet received on 15: 1234, 5678, 9101

经过一番摆弄后,他告诉我,如果他不data32将 struct 的成员强制转换为 a ,他会得到正确的输出uint32_t*

根据我自己的研究,packet是 type csp_packet_t,定义为:

typedef struct __attribute__((__packed__)) {
        uint8_t padding[CSP_PADDING_BYTES];     // Interface dependent padding
        uint16_t length;                        // Length field must be just before CSP ID
        csp_id_t id;                            // CSP id must be just before data
        union {
                uint8_t data[0];                // This just points to the rest of the buffer, without a size indication.
                uint16_t data16[0];             // The data 16 and 32 types makes it easy to reference an integer (properly aligned)
                uint32_t data32[0];             // - without the compiler warning about strict aliasing rules.
        };
} csp_packet_t;

完整的头文件在这里

这是 GNU C,因此允许使用零长度数组

我不知道两边架构的字长或字节序。

所以,简单地说——这里发生了什么?为什么演员阵容很重要?

4

3 回答 3

2

21822844980x821304D2哪里0x04d21234,其余的可能是数据包数据。更多,不知道如何csp_send和相应的接收器看起来(即:显示更多代码)是无法分辨的。

而这一行:memcpy(packet->data32, data, sizeof(data));实际上是缓冲区溢出错误...因为您没有为packet->data32

于 2014-03-27T09:28:09.147 回答
1

我认为这是一个对齐问题。

引用fritzone:

2182284498 是 0x821304D2 其中 0x04d2 是 1234 其余可能是数据包数据

这是因为联合是打包结构的成员,它有 16 位不对齐。当从打包结构中的联合成员访问时,编译器会使用一些魔法来确保正确检索打包(未对齐)数据。但是,当转换为uint32_t*编译器时会丢失打包细节,我相信它假定它正在访问正确对齐的数据。

于 2014-03-27T09:57:25.197 回答
-1

数组的大小不能为零。此代码使用一些非标准 C 甚至使联合编译。所以在那个工会内部发生了什么,没人知道。就 C 语言而言,这是未定义的行为。

由于程序在遇到未定义的行为时会执行“任何操作”,因此它可以按预期工作。

于 2014-03-27T09:30:10.950 回答