Re: Using flags

From: Arthur J. O'Dwyer (ajo_at_nospam.andrew.cmu.edu)
Date: 01/09/05


Date: Sat, 8 Jan 2005 21:52:25 -0500 (EST)


On Sat, 8 Jan 2005, xm wrote:
[re: bitflags]
> As I understand with an (int) I have 16 bit of play.

   15 bits, technically, since plain 'int' is signed and you're not really
allowed to mess around with the sign bit. The real explanation is more
complicated, but it turns out that it doesn't matter, because you should
never used signed types for anything bit-related in C or C++.

   Use 'unsigned int' for a full 16 bits of play, or 'unsigned long' for
32. I recommend 'unsigned long', since on most modern machines it's going
to take 32 bits no matter what you do. Occasionally I find that

     unsigned flags; /* unsigned int, 16 flags' worth */

is clearer and no less useful than

     unsigned long flags; /* 32 flags' worth */

("What's long about them?" thinks the reader), but that's up to you.

> I've seen that I could use flags this way:
>
> SomeFunction(FLAG_ONE | FLAG_TWO | FLAG_THREE)
>
> But could you tell me:
> 1) what would be the definition of SomeFunction()

   void SomeFunction(unsigned long flags);

> 2) what would be the definition of FLAG_ONE, etc...

     #define FLAG_ONE 0x0001
     #define FLAG_TWO 0x0002
     #define FLAG_THREE 0x0004
     #define FLAG_FOUR 0x0008
     #define FLAG_FIVE 0x0010
     [...]

You could also use enums, or in C++ you could even use static const
members of a class, but I'll stick with the old-fashioned way. I like
the #define way because it makes everything line up easily, and doesn't
have those cluttery '=' signs everywhere. :)

> 3) inside SomeFunction(){}, how can I check to see if FLAG_ONE is set,
> etc...
>
> I am not sure, I've had LogicMath course at the university and I guess it
> would be:
>
   void SomeFunc(unsigned long Flags)
   {
> if(Flags & FLAG_ONE == FLAG_ONE){ /*Flag one is set */ }
> else { /* it's not */ }
> }

That will work. It tests all the bits in FLAG_ONE at once, though,
which in this case is irrelevant, but consider

     #define FLAG_ONE 0x0001 /* et cetera, as above */
     #define FLAG_ONE_AND_THREE 0x0005 /* == FLAG_ONE | FLAG_THREE */
     #define FLAG_FOUR_AND_FIVE 0x0018 /* == FLAG_FOUR | FLAG_FIVE */

     void SomeFunction(unsigned long flags)
     {
         if (flags & FLAG_ONE)
           puts("Flag 1 is set.");
         if (flags & FLAG_ONE_AND_THREE)
           puts("At least one of Flags 1 and 3 is set.");
         if (flags & FLAG_ONE_AND_THREE == FLAG_ONE_AND_THREE)
           puts("Both of Flags 1 and 3 are set.");
         if (flags & (FLAG_ONE_AND_THREE | FLAG_FOUR_AND_FIVE))
           puts("At least one of Flags 1, 3, 4, and 5 is set.");
         if (~flags & FLAG_ONE)
           puts("Flag 1 is not set.");
         if (~flags | FLAG_ONE == ~flags)
           puts("Flag 1 is set!");
         flags &= ~FLAG_ONE; /* turns Flag 1 off */
         flags |= FLAG_ONE; /* turns Flag 1 on */
     }

...And so on. Google for a tutorial on bitwise operators if you need a
refresher, but most of what you'll need isn't even pencil-and-paper stuff.

HTH,
-Arthur