这是如何运作的?
struct {
int a : 21;
int b : 11;
};
a 和 b 是两个独立的 int 变量还是使用不同位域的同一个变量?
这些是 中的两个单独的变量struct
,一个是命名的a
,一个是命名的b
。但是,它们的大小a
应该有 21 位并且b
应该有 11 位。访问一个变量并对其进行操作不会影响另一个变量。
希望这可以帮助!
这里的“变量”是什么意思并不完全清楚。如果您的意思是可以获取地址的内存,那么位域不符合描述,因为它们是“可寻址存储单元”的一部分。如果“变量”的意思是“我可以在其中存储一些值的位集”,那么 a 和 b 看起来都像结构中的任何其他字段。
不过,足够的语义吹毛求疵。让我们去源头:
C99 标准中的 ch 6.7.2.1 说:
10 一个实现可以分配任何大到足以容纳位域的可寻址存储单元。如果有足够的空间,结构中紧跟在另一个位域之后的位域应该被打包到同一单元的相邻位中。如果剩余空间不足,则是否将不适合的位域放入下一个单元或与相邻单元重叠是由实现定义的。一个单元内位域的分配顺序(高位到低位或低位到高位)是实现定义的。可寻址存储单元的对齐方式未指定。
因此,根据编译器选择的“可寻址存储单元”,您的 a 和 b 可能最终会出现在不同的“存储单元”中,具体取决于编译器的具体情况。
这取决于系统架构如何实现。如果你举一个更直接的例子:
struct x {
uint8_t a : 2;
uint8_t b : 3;
};
这里可能a
会b
共享相同的内存字节,例如:xxxb bbaa(其中 x 未使用)。
我相信对齐和打包的语义是未定义的 - 最好尝试一下!如果您正在做一个多平台项目,请注意不同的硬件(甚至可能是编译器)。
struct x s;
s.a = 3;
s.b = 5;
printf("0x%02X\n", *((char*)&s) );
输出可能是0x03
、或什至0x05
中的任何一个。0x16
0x25
我希望看到0x16
...
我认为,在传输位域时,您应该始终手动构建已知状态。
uint8_t buf[];
buf[x] = 0;
buf[x] |= (s.a) & 0x03;
buf[x] |= (s.b << 2) & 0x1C;