我以前有过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;
}
答案 0 :(得分:4)
位域比显式位掩码更易于使用,尤其是对于长度大于1的掩码。经常以微妙的方式破坏手工编码的位扭曲。
位域的主要问题是规范不精确:
由实现定义,带符号的类型的位字段是否可以具有负值。
存储器中位域的顺序和位置是实现定义的,这消除了硬件映射的风险。即使对于给定的字节序,位域的位置和顺序也无法精确指定,这是一个主要缺点。
尤其要注意,int field_a : 1;
实际上是不正确的:具有单个位的int
位字段可能会被读取为-1
而不是1
(如果已设置)。您应该写unsigned int field_a : 1;
答案 1 :(得分:0)
我知道人们可以使用位掩码来隔离数据结构中的某些位,但是为什么要麻烦位域呢?
一个人使用位域来映射一个数据结构,该数据结构的字段大小并非全部与C实现的内置类型(例如TCP报头)匹配,或者只是缩小数据结构的大小。
您确实可以通过使用掩码和移位来手动打包和解压缩数据,但是位字段为此提供了更方便的语法。除了隐藏移位和屏蔽之外,在适当的情况下,位域访问还可以透明地处理符号扩展问题和_Bool
的特殊特征。
权衡是对细节失去控制。如果您手动打包和解包,则可以完全放心并控制布局,并具有出色的可移植性。另一方面,如果您使用位域,则和会关心位的排列方式细节,那么您需要依靠实现细节或扩展来确保您拥有所需的布局,甚至完全可以从您的实施中实现。