【发布时间】:2017-09-15 11:29:30
【问题描述】:
我正在开发一些嵌入式软件,并试图让事情变得更加灵活。我希望能够做的一件事是更改结构并在整个应用程序的其余部分更改数据处理方式。
我注意到我可以将 一些 数据从有效负载复制到联合中,但由于某种原因不能全部复制。这是我正在做的事情:
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。
任何帮助或指导将不胜感激。
【问题讨论】:
-
我猜这与结构填充有关。如果你使用你的编译器编译指示或类似的东西来打包没有填充的结构怎么办?
-
啊哈,你成功了!对结构还不够熟悉,无法了解填充/打包。做了一些谷歌搜索,发现我的编译器支持 attribute__((__packed)),所以我把 PacketHeader 放在前面,这一切都不同了。非常感谢!
-
强制警告:应避免滥用结构用于序列化目的,因为对字节序和填充的控制是有限的。建议单独处理每个结构成员。
-
@user694733,你能详细说明一下吗?
-
您的问题是该问题的一个典型例子:要解决它,您必须求助于编译器特定的功能,这限制了代码的可移植性。我引用我不久前对类似帖子的评论:“您可以从阅读this wikipedia article 或this SO question 开始。网上有很多关于这方面的信息。”
标签: c struct embedded unions memcpy