1

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;
shipshape
  • 691
  • 1
  • 6
  • 5

2 Answers2

2

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.

  • thanks for the helpful reply. Ideally I would like the equivalent of (flag & ~(1 << FOO_BITPOSITION)) where the check can be done on the fly. Creating a constant in advance seems a bit clunky - I'll need a separate constant for every field I need to check. The problem is that the named bitfields are intended to make it hard to get at FOO_BITPOSITION... sigh. – shipshape May 14 '15 at 13:09
  • The problem is that the actual order of bits in your struct is compiler dependent as per the C spec. In the format of your example, though, you can do ~((flag ^ ~(1 << FOO_BITPOSITION)) - 255u) – R Phillip Castagna May 14 '15 at 14:09
  • You can also just use another instance of the same struct, and programmatically set the bit you want to be 1 to 0 and everything else to 1, then do the XOR. That way you could even do stuff like loop through the fields on the struct to see what matched if you wanted. – R Phillip Castagna May 14 '15 at 14:12
0

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'.

Community
  • 1
  • 1
ChuckCottrill
  • 4,360
  • 2
  • 24
  • 42
  • Thanks for the thorough examples. But these all help with the individual field. Any suggestions for how to check if foo is the only field set without creating a flags_t variable? The equivalent of "if (flag & ~(1 << FOO_BITPOSITION)) " – shipshape May 14 '15 at 08:37