uint12 结构中的字节序

Endianness within uint12 struct

本文关键字:字节 结构 uint12      更新时间:2023-10-16

假设我有数据,如下所示:

union
{
struct
{
char flags : 4;
uint16_t   : 12;
}
char data[2];
}

我了解如何使此代码运行,而不管平台上的字节字节序如何。我要求确保我对如何在不同的字节序上存储它的理解是正确的。

据我了解: 如果我在 12 位 uint 中存储一个 uint16,两个字节序都会丢弃 4 个最高位。Big-endian 会将剩余的 4 个高位存储在与标志相同的字节中,其余的存储在单独的字节中。Little-endian 会将 4 个最低位存储在与标志相同的字节中,其余的存储在单独的字节中。

这是对的吗?

这取决于编译器和目标平台的 ABI。例如,请参阅GCC位域的规则:单元内位字段的分配顺序由ABI确定。此外,每个字段都应该声明为intunsigned int,而不是uint16_t

如果要控制数据格式,可以使用移位和掩码将数据组合成uint16_t。如果您的目标是以明确定义的格式写出数据,则可以以所需的字节序写入uint16_t字节,或者只是将数据组合成 2 个字节并按所需的顺序写入它们。

除非你找到承诺你想要的语言规范文档,或者你的编译器文档做出了明确的承诺,并且你对大端和小端 CPU 使用相同的编译器,否则不要依赖 C/C++ 编译器都以相同的方式做这样的事情。

Little-endian 会将 4 个最低位存储在与标志相同的字节中

我熟悉的所有编译器只有在它们的基本存储单元相同时才组合相邻的位域(尽管其中一个可爱的实现定义细节)。因此,在您的示例中,将charuint16_t混合会破坏将它们组合在一起,这意味着该结构将使用 3 个字节(对于任一字节序)。对两个字段使用相同的基本类型可以得到你想要的(但static_assert(sizeof(...) == 2)以防万一):

union
{
struct
{
uint16_t flags : 4;
uint16_t value : 12;
}
uint8_t data[2];
}

每个位布局为:

绝对位字节位 字节位BE 顺序#0 012345V167
字节 LE 顺序1 BE 顺序#2
0F0 V8V4
01F1 V9V5
02F2VAV6
03F3VBV7
04 V0F0V8
05F1V9
06V2 F2VA
07 V3F3VB
810V4 V0F0
91 1V5V1 F1
1012V6 V2F2
111 3V7 V3F3
121 4V8 V4V0
131 5V9 V5V1
1416VAV6 V2
1517VBV7 V3