我在 Cortex-M4 微 Controller 上有一些代码,想使用二进制协议(protocol)与 PC 通信。目前,我正在使用使用 GCC 特定的 packed
属性的打包结构。
这是一个粗略的大纲:
struct Sensor1Telemetry {
int16_t temperature;
uint32_t timestamp;
uint16_t voltageMv;
// etc...
} __attribute__((__packed__));
struct TelemetryPacket {
Sensor1Telemetry tele1;
Sensor2Telemetry tele2;
// etc...
} __attribute__((__packed__));
我的问题是:
TelemetryPacket
结构使用完全相同的定义,上述代码是否可以跨多个平台移植? (我对 x86 和 x86_64 感兴趣,需要它在 Windows、Linux 和 OS X 上运行。)编辑:
最佳答案
考虑到上述平台,是的,打包结构完全可以使用。 x86 和 x86_64 始终支持非对齐访问,与普遍看法相反,这些平台上的非对齐访问在很长一段时间内与对齐访问具有 (almost) 相同的速度(不存在未对齐访问慢得多的情况)。唯一的缺点是访问可能不是原子的,但我认为在这种情况下并不重要。并且编译器之间有约定,packed structs会使用相同的布局。
GCC/clang 支持使用您提到的语法的打包结构。 MSVC有#pragma pack
,可以这样使用:
#pragma pack(push, 1)
struct Sensor1Telemetry {
int16_t temperature;
uint32_t timestamp;
uint16_t voltageMv;
// etc...
};
#pragma pack(pop)
可能会出现两个问题:
movaps
或 ldrd
),那么使用该指针可能会导致崩溃(gcc 不会对此发出警告,但 clang 会发出警告)。这是来自 GCC 的文档:
The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable
所以 GCC 保证不会使用任何填充。
MSVC:
To pack a class is to place its members directly after each other in memory
所以 MSVC 保证不会使用任何填充。
我发现的唯一“危险”领域是位域的使用。那么 GCC 和 MSVC 之间的布局可能会有所不同。但是,GCC 中有一个选项可以使它们兼容:-mms-bitfields
提示:即使这个解决方案现在可以工作,而且它不太可能停止工作,我建议您保持代码对这个解决方案的依赖性较低。
注意:我在这个答案中只考虑了 GCC、clang 和 MSVC。可能有编译器,但这些事情是不正确的。
https://stackoverflow.com/questions/45116212/