我有以下样式的联合 - 在界面中定义,因此不容易更改。
我想检查foo是否是唯一被设置的字段。并且不希望通过逐项列出所有其他字段。
所以我的直接想法是构建一个掩码,但是bitfield正在做它最好隐藏详细信息,比如命名字段的位置。
我想不出比用一个字段集创建变量然后反转原始字段更好的事情。有更整洁的解决方案吗?
typedef union struct {
unsigned char user:1;
unsigned char zero:1;
unsigned char foo:1;
unsigned char bar:1;
unsigned char blah:1;
unsigned char unused:3;
};
unsigned char raw;
} flags_t;
答案 0 :(得分:2)
按位异或,否定你想要的东西:
11011111
^ 00100000
= 11111111
然后检查值== 255.通过使用自己的结构来构建否定,可以通过将bar-> foo = 0和其他所有内容设置为1来使其清除。
编辑:稍微详细一点,因为当你要求的时候,我觉得自己很不舒服:
struct {
unsigned char bad:1;
unsigned char bad:1;
unsigned char foo;
unsigned char other:1;
unsigned char bad:1;
unsigned char things:3;
} state_checker;
int some_checking_function(flags_t possible_foo) {
result = possible_foo ^ state_checker;
result = !(result - 255u);
return result;
}
理想情况下,你甚至会创建一个使用与你正在检查的值相同的结构的常量,以确保在编译时没有任何不可思议的事情,但这是基本的想法。
答案 1 :(得分:0)
位域中每个位的确切位置取决于实现。但是编译器会做一致的事情,所以一旦你确定你关心的位在你的union / struct中,你可以构造一个掩码。
正如您所推断的,您可以为位域中的任何命名位构造一个掩码,并使用set / clear / toggle / check操作对其进行操作。 This question shows how为单个位(在C中)执行上述操作。下面提供的函数显示了如何使用并集的原始部分访问set,clear和toggle(假设原始部分的大小与分配的位域部分相同。
如何检查/访问联盟中的foo,
fooget( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
return(foo = flag.raw & mask.foo);
}
如何使用按位运算符和掩码
清除foofooclear( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
return( flag.raw &= ~mask.raw );
}
如何使用raw和mask
上的按位运算符设置foofooset( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
flag.raw |= mask.raw;
}
如何使用带掩码的raw运算符来切换(反转/翻转)foo,
footoggle( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
flag.raw ^= mask.raw;
}
警告:这与bitfields的精神背道而驰,后者隐藏了位操作的细节,使这些位操作“更容易”。