我正在为32位MCU读取此代码。
我的问题是 - 是否有必要使用__attribute__((packed, aligned(1)))
?这只是一种很好的做法,或者如果没有它会导致不可预测的行为。
typedef struct __attribute__((packed, aligned(1))) radio_packet {
uint8_t tag; /* 1 byte */
uint32_t id; /* 4 bytes */
uint16_t size; /* 2 bytes */
uint16_t element; /* 2 bytes */
uint8_t length; /* 1 byte */
// The items above comprise HDR_SIZ
uint8_t data[PKT_SIZ];
} radio_packet_t;
答案 0 :(得分:3)
这是不错的做法还是会导致不可预测的行为呢?
两者都不是。如果打包与否的数据只在程序中使用,那么最好让编译器选择如何排序这些数据以及如何对齐它们 - 除非你真的想保存ram。
如果数据必须具有特定格式 - 我认为是,因为您的结构名为“radio_packet”,那么您需要确保您所编写的格式受到尊重。在这种情况下,您希望打包数据,并在格式请求时手动插入填充。
在这种特殊情况下,结构的名称让我认为数据包将被传输到其他设备,这些设备将运行可能使用不同编译器编写的软件。因此,您不希望编译器干扰字段的顺序和位置。换句话说,该结构仅在程序中使用。
进一步扩展。在正常情况下,不使用 打包和/或对齐是一种很好的做法,因为编译器比人类更了解什么是最好的。当您知道比编译器做得更好时,可以使用打包/对齐,例如,因为您必须遵守编译器不知道的某种格式。通常(但取决于编译器),它可以选择优化性能,也许会浪费一些内存。为了获得最大性能,它可以将字段与CPU的首选对齐方式对齐,插入未使用/隐藏的字段,甚至重新排序。如果您随后将该数据包发送到某些不使用相同填充/对齐的硬件或软件,这是不好的:32位CPU更喜欢32位对齐数据,但8位CPU无关紧要。 / p>
从程序/ CPU的角度来看,在任何一种情况下都不会出现不可预测的行为。编译器非常清楚它正在做什么,即使你强加了一些限制。当数据格式错误,进入/退出程序时,会发生错误或[可能不那么]不可预测的行为。
答案 1 :(得分:0)
没有必要,但您可以稍后在代码中进行假设。例如,您可以从char数组到radio_packet_t执行安全memcpy,并且程序中的所有组件都不需要知道类型radio_packet_t,并且可以使用字节缓冲区通过networkd或文件或其他任何方式发送radio_packet_t。