我正在开发一些嵌入式软件,并试图让事情变得更加灵活。我希望能够做的一件事就是更改一个结构,并在整个应用程序的其余部分中处理数据的变化。
我注意到我可以将某些数据从有效负载复制到联合中,但由于某种原因并非全部。这就是我正在做的事情:
union ConcentratorPacket {
struct PacketHeader header;
struct NetworkJoinReqPacket networkJoinReqPacket;
};
static union ConcentratorPacket latestRxPacket;
其中:
struct PacketHeader {
uint32_t sourceAddress;
uint8_t packetType;
};
struct NetworkJoinReqPacket{
struct PacketHeader header;
uint8_t maxDataLen;
};
稍后我想将收到的数据包中的数据移动到这个联合中的相关结构中,所以我想这样做:
memcpy(&latestRxPacket.networkJoinReqPacket, rxPacket->payload, sizeof(latestRxPacket.networkJoinReqPacket));
其中rxPacket->payload
是uint8_t的数组,以正确的顺序发送。
我看到的是packetHeader很好地填充了这个方法,但是maxDataLen没有采用正确的值。实际上,它所需要的值是有效载荷[8]而不是有效载荷[5]。
我发现解决这个问题的唯一方法是直接分配maxDataLen,但如果结构因任何原因发生变化,那么每个地方都需要更改,所以memcpy更可取而不是这样:
memcpy(&latestRxPacket.networkJoinReqPacket.header, rxPacket->payload, sizeof(latestRxPacket.networkJoinReqPacket.header));
latestRxPacket.networkJoinReqPacket.maxDataLen = rxPacket->payload[5];
我认为我所看到的内容表明memcpy将maxDataLen视为uint32,这是正确的,但我不知道如何避免这种情况。
这很奇怪,因为我在其他地方做了类似的事情并且工作正常,但唯一的区别是相当于maxDataLen是uint32,而不是uint8。
非常感谢任何帮助或指示。
答案 0 :(得分:0)
正如一些程序员老兄指出的那样,它与struct padding / packing有关。默认情况下,我在Code Composer Studio中使用的TI编译器会将结构填充为与32位内存对齐。
幸运的是,编译器支持__attribute__((__packed__))
。
只需更改PacketHeader
的定义即可解决问题:
struct __attribute__((__packed__)) PacketHeader {
uint32_t sourceAddress;
uint8_t packetType;
};
答案 1 :(得分:0)
使用“packed”结构时要小心 - 根据目标cpu的详细信息,很容易获得非对齐访问,这可能是非法的或仅仅是低效的。考虑重新安排结构类型以避免需要“打包”。
当您使用结构体进行此类操作时,我建议在编译器上使用“-Wpadded”。这将让编译器告诉您何时添加了填充结构。如果您期望填充,请明确添加(例如“uint8_t dummy [3];”)。
还要慷慨地使用_Static_assert来检查结构是否符合预期。你的目标是不匹配产生编译时错误,而不是等待测试和调试。