我试图制作一种更好的类型来处理发送到 LED 驱动器 IC 的打包数据。格式看起来像这样。它显示两种可能的格式,具体取决于
Address
位的值。请注意,MSB 显示在右侧,而不是左侧,并且应该是移入 IC 的第一位:
我尝试编写一个联合类型来解决这个问题,但它不断扩展到 5 个字节。所以我决定尝试写这个:
struct Color {
uint8_t ignore : 1;
uint8_t address : 1;
uint16_t red : 10;
uint16_t green : 10;
uint16_t blue : 10;
Color()
:
ignore(0),
address(0),
red(0),
green(0),
blue(0)
{
}
} __attribute__((packed));
从结构体的开头按顺序转储字节(在 M1 MacBook Pro 上,用 Clang 编译,所以是小端)给我:
Color c;
c.ignore = 1;
dump(&c, sizeof(c));
01 00 00 00
我期待
80 00 00 00
。如果我将 address
和 ignore
放在结构体的末尾,我会得到 00 00 00 80
,这也是意料之外的。
是否可以编写这样的类型,使所有位都按照预期的顺序打包到 4 个字节中?我意识到在分配给
uint16_t
值时也可能存在字节序问题,但我认为我可以处理这个问题。
为此,您不应该使用位字段,而应该使用位移位和位屏蔽。遗憾的是,位字段因编译器而异,您不能依赖正确的字节顺序。
如 C99 标准 6.7.2.1:10 所述:
实现可以分配任何足够大的可寻址存储单元来容纳位字段。如果还有足够的空间,则紧接着另一个位字段的位字段 结构应打包到同一单元的相邻位中。如果剩余空间不足, 不适合的位域是否被放入下一个单元或与相邻单元重叠 实现定义的。单元内位域的分配顺序(高位到 低阶或低阶到高阶)是实现定义的。的对齐方式 可寻址存储单元未指定。