强制结构大小为 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。
我有一个应该是 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。