在C中使用位字段时的字段顺序

我有一个以下类型的结构

typedef struct { unsigned int a : 8; unsigned int b : 6; unsigned int c : 2; }x, *ptr; 

我想做的是改变字段c的值。

我做了类似以下的事情

 x structure = { 0 }; x->c = 1; 

当我查看内存映射时,我希望找到00 01 ,但我找到00 40 。 看起来在排列第二个字节时,它将c字段放在最低位中,将b字段放在最高位中。 我在GCC和Windows编译器上都看到了这一点。

现在,我做的是以下,这是正常的。

 unsigned char ptr2 = (unsigned char*) ptr *(ptr2 + 1) &= 0xFC *(ptr2 + 1) |= 0x01 

我看内存图错了吗? 谢谢您的帮助。

C标准允许编译器以任何顺序放置位域。 没有可靠且便携的方式来确定订单。

如果您需要知道确切的位位置,最好使用普通无符号变量和位屏蔽。

这是使用位域的一种可能的替代方法:

 #include  #define MASK_A 0x00FF #define MASK_B 0x3F00 #define MASK_C 0xC000 #define SHIFT_A 0 #define SHIFT_B 8 #define SHIFT_C 14 unsigned GetField(unsigned all, unsigned mask, unsigned shift) { return (all & mask) >> shift; } unsigned SetField(unsigned all, unsigned mask, unsigned shift, unsigned value) { return (all & ~mask) | ((value << shift) & mask); } unsigned GetA(unsigned all) { return GetField(all, MASK_A, SHIFT_A); } unsigned SetA(unsigned all, unsigned value) { return SetField(all, MASK_A, SHIFT_A, value); } /* Similar functions for B and C here */ int main(void) { unsigned myABC = 0; myABC = SetA(myABC, 3); printf("%u", GetA(myABC)); // Prints 3 } 

我知道这是一个旧的,但我想补充一下我的想法。

  1. C中的标题可以跨对象使用,这意味着编译器必须在某种程度上保持一致。

  2. 根据我的经验,我总是看到LSB顺序的位域。 这将把位置为MSB-> LSB顺序为c:b:a

以字节顺序读取的16位是“00 40”。 从Little-endian翻译,这是一个16位值0x4000。

这是:

 c == [15:14] == b'01 b == [13:8] == 0 a == [7:0] == 0 

内存总是取决于底层机器结构(字节顺序)以及打包/排列编译器正在执行的结构的策略。

您将C结构设置为原始位,这是您的危险。

你知道这些位是什么意思,所以你可以填写结构的字段。 是的,它比memcpy更多的代码,但如果有人添加字段,它将不会中断,并且如果有助于在通信级别强制执行位级特异性。