强制结构大小为 8 字节

Enforce struct size 8 byte

我有一个应该是 8 字节大小的结构。

struct Slot {
    uint8_t T;
    uint8_t S;
    uint32_t O : 24;
    uint32_t L : 24;
}

但是,sizeof(Slot) 告诉我大小是 12 字节。 所以编译器似乎填充了数据,尽管它不是必需的(可能是因为 24 位无法正确对齐)。

一个 hacky 解决方案是使用 3 个单字节字段而不是单个三字节字段:

struct Slot2 {
    uint8_t T;
    uint8_t S;
    uint8_t O1;
    uint8_t O2;
    uint8_t O3;
    uint8_t L1;
    uint8_t L2;
    uint8_t L3;
}; // sizeof(Slot2) = 8

还有其他方法可以实现吗?

尝试如下所示:

struct Slot {
    uint32_t O : 24;
    uint8_t T;
    uint32_t L : 24;
    uint8_t S;
};

我认为,你想要的 8 字节,不是 C 标准可以保证的,你的第一个定义。

相关:来自 C11 标准,章节 §6.7.2.1,

An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.

不过你还是有办法的,如果你可以调整变量,使它们可以适合 32位对齐,那么

24 + 8 + 24 + 8 = 64 位 = 8 字节。

你可以有一个大小为 8 字节的结构。

这在 MSVC 上给出了 8 字节大小,没有打包编译指示。

struct Slot {
    uint32_t O : 24;
    uint32_t T : 8;
    uint32_t L : 24;
    uint32_t S : 8;
};

您的 "hack" 解决方案完全正确。我怀疑布局是由一些外部因素决定的,因此您无法以任何更好的方式将其映射到结构。我怀疑你的 24 位数字中的字节顺序也是由外部决定的,而不是由你的编译器决定的。

要处理这种情况,字节结构或字节数组是最简单且可移植的解决方案。

任何人都无法知道您的代码将做什么或数据将如何在内存中结束,因为位域的行为在 C 标准中没有明确规定。 See this.

  • 未指定当您对位字段使用 uint32_t 时会发生什么。
  • 你不知道是否会有填充位。
  • 你无法知道是否会有填充字节。
  • 您无法知道填充位或字节将在哪里结束。
  • 您无法知道第二个 24 位块的 8 位是紧接在前一个数据之后结束,还是与下一个 32 位段对齐。
  • 您无法知道哪个位是 msb 哪个位是 lsb。
  • 字节顺序会导致问题。

解决方案是根本不使用位域。请改用按位运算符。

使用此依赖于编译器的解决方案(适用于 gcc、msvc),结构将为 8 个字节:

#pragma pack(push, 1)
struct Slot {
    uint8_t T;
    uint8_t S;
    uint32_t O : 24;
    uint32_t L : 24;
};
#pragma pack(pop)

这会将结构的对齐设置为 1 个字节。

在 MSVC 上,以下内容有效并使您的变量顺序保持不变:

struct Slot {
    uint64_t T : 8;
    uint64_t S : 8;
    uint64_t O : 24;
    uint64_t L : 24;
};

但这并不能保证跨编译器。其他编译器上的 YMMV。