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

时间:2013-10-15 08:25:25

标签: c gcc bit-manipulation bit bit-fields

我有以下类型的结构

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

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

4 个答案:

答案 0 :(得分:13)

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

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

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

#include <stdio.h>

#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 :(得分:3)

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

  1. C中的标题可以跨对象使用,这意味着编译器必须有些一致。

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

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

    这是:

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您可以将C结构设置为原始位。

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