shipshape
shipshape

Reputation: 711

How to check for a single field being set in a C bitfield

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

Answers (2)

R Phillip Castagna
R Phillip Castagna

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

ChuckCottrill
ChuckCottrill

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

Related Questions