位域VS。位掩码

时间:2019-07-09 17:22:08

标签: c bit-manipulation bit-fields bitmask

我以前有过C方面的经验,但是我以前从未见过位域功能。我知道可以使用位掩码来隔离数据结构中的某些位,但是为什么要麻烦位域呢?

例如,说我们要隔离的位是前3个最低有效位。然后我们可以写:

/* our bitmasks */
#define FIELD_A (1 << 0)
#define FIELD_B (1 << 1)
#define FIELD_C (1 << 2)

int main(void) 
{ 
    /* the data structure that contains our three fields */
    uint8_t flags;

    /* accessing field A (as a boolean) */
    int bool_a = !!(flags & FIELD_A);

    /* accessing field B (as a boolean) */
    int bool_b = !!(flags & FIELD_B);

    /* accessing field C (as a boolean) */
    int bool_c = !!(flags & FIELD_C);

    return 0;
}

为什么我们选择将其写为:

static struct fields {
    int field_a : 1;
    int field_b : 1;
    int field_c : 1;
};

int main(void) 
{ 
    /* the data structure that contains our three fields */
    struct fields flags;

    /* accessing field A */
    int bit_a = flags.a;

    /* accessing field B */
    int bit_b = flags.b;

    /* accessing field C */
    int bit_c = flags.c;

    return 0;
}

2 个答案:

答案 0 :(得分:4)

位域比显式位掩码更易于使用,尤其是对于长度大于1的掩码。经常以微妙的方式破坏手工编码的位扭曲。

位域的主要问题是规范不精确:

  • 由实现定义,带符号的类型的位字段是否可以具有负值。

  • 存储器中位域的顺序和位置是实现定义的,这消除了硬件映射的风险。即使对于给定的字节序,位域的位置和顺序也无法精确指定,这是一个主要缺点。

尤其要注意,int field_a : 1;实际上是不正确的:具有单个位的int位字段可能会被读取为-1而不是1(如果已设置)。您应该写unsigned int field_a : 1;

答案 1 :(得分:0)

  

我知道人们可以使用位掩码来隔离数据结构中的某些位,但是为什么要麻烦位域呢?

一个人使用位域来映射一个数据结构,该数据结构的字段大小并非全部与C实现的内置类型(例如TCP报头)匹配,或者只是缩小数据结构的大小。

您确实可以通过使用掩码和移位来手动打包和解压缩数据,但是位字段为此提供了更方便的语法。除了隐藏移位和屏蔽之外,在适当的情况下,位域访问还可以透明地处理符号扩展问题和_Bool的特殊特征。

权衡是对细节失去控制。如果您手动打包和解包,则可以完全放心并控制布局,并具有出色的可移植性。另一方面,如果您使用位域,则会关心位的排列方式细节,那么您需要依靠实现细节或扩展来确保您拥有所需的布局,甚至完全可以从您的实施中实现。