Reputation: 711
I have the following style of union - defined in an interface so not easy to change.
I want to check if foo is the only field being set. And don't want to this by itemizing all the other fields.
So my immediate thoughts were to construct a mask, but then the bitfield is doing it's best to hide details like the position of a named field.
I couldn't think of anything better than creating a variable with the one field set and then inverting the raw field. Is there a neater solution?
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;
Upvotes: 1
Views: 170
Reputation: 896
Bitwise XOR with the negation of what you want:
11011111
^ 00100000
= 11111111
Then just check that the value == 255. Can make it clean by using your own struct to build the negation by setting bar->foo = 0 and everything else to 1.
edit: A little elaboration because I feel bad about not being pretty when that's what you're asking for:
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;
}
Ideally you would even make a constant that uses the same struct that the value you're checking uses, to make sure that nothing wonky happens at compile time, but this is the basic idea.
Upvotes: 2
Reputation: 4444
The exact position of each bit in a bitfield is implementation dependent. But the compiler is going to do consistent things, so once you determine where the bit(s) you care about lie in your union/struct, you can construct a mask.
As you have deduced, you can construct a mask for any named bit in a bitfield, and operate on it using set/clear/toggle/check operations. This question shows how to do the above operations for a single bit (in C). The functions provided below show how to access set, clear, and toggle a bit, using the raw part of the union (assuming the raw part is the same size as the bitfield part allocated.
How to check/access foo, a bit in the union,
fooget( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
return(foo = flag.raw & mask.foo);
}
How to clear foo, using bitwise operators and mask
fooclear( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
return( flag.raw &= ~mask.raw );
}
How to set foo, using bitwise operator on raw and mask
fooset( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
flag.raw |= mask.raw;
}
How to toggle (invert/flip) foo, using bitwise operators on raw with a mask,
footoggle( flags_t flag )
{
flags_t mask;
mask.raw = 0;
mask.foo = 1;
flag.raw ^= mask.raw;
}
Warning: this is contrary to the spirit of bitfields, which are about hiding the details of bit manipulations, making these bit manipulations 'easier'.
Upvotes: 0