c++ - 打包结构是可移植的吗?

我在 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__));

我的问题是:

  • 假设我对 MCU 和客户端应用程序上的 TelemetryPacket 结构使用完全相同的定义,上述代码是否可以跨多个平台移植? (我对 x86 和 x86_64 感兴趣,需要它在 Windows、Linux 和 OS X 上运行。)
  • 其他编译器是否支持具有相同内存布局的打包结构?用什么语法?

编辑:

  • 是的,我知道打包结构是非标准的,但它们似乎很有用,可以考虑使用它们。
  • 我对 C 和 C++ 都感兴趣,尽管我不认为 GCC 会以不同的方式处理它们。
  • 这些结构不被继承,也不继承任何东西。
  • 这些结构仅包含固定大小的整数字段,以及其他类似的打包结构。 (我以前被花车烧过……)

最佳答案

考虑到上述平台,是的,打包结构完全可以使用。 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)

可能会出现两个问题:

  1. 跨平台的字节序必须相同(您的 MCU 必须使用小字节序)
  2. 如果您将指针分配给压缩结构成员,并且您使用的架构不支持非对齐访问(或使用具有对齐要求的指令,例如 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/

相关文章:

c++ - 向 Python 公开 C++ API

c++ - 标准的 atomic bool 和 atomic flag 之间的区别

c++ - 为什么 unique_ptr 实例化编译为比原始指针更大的二进制文件?

c++ - C 和 C++ 中的多字 rune 字

c++ - QObject 多重继承

c++ - 访问类中定义的 friend 功能

c++ - 在 C++ 中设置本地环境变量

c++ - 为什么我们在 C++ 中使用 std::function 而不是原来的 C 函数指针?

c++ - 为什么这个包含 rand() 的 C++11 代码多线程比单线程慢?

c++ - 为 Windows 编写超薄 C++ 程序(如 uTorrent)