views:

134

answers:

4

Ok I want to add some sort of flag like variable to one of my classes and had some questions about going about doing it. After looking at some source that uses it I noticed some stuff like this.

TEXTUREFLAGS_POINTSAMPLE = 0x00000001,
TEXTUREFLAGS_TRILINEAR = 0x00000010,

Does the way this work is by combining all the flags into one int? so like if I had both of these like TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_TRILINEAR it would be the value 0x00000011?

So do I need to offset the bytes like this or am I good to just use straight ints? Like:

TEXTUREFLAGS_POINTSAMPLE = 1;
TEXTUREFLAGS_TRILINEAR = 2;
+5  A: 

Your first method isn't using the bits in the most efficient manner. In the first example you are using hexadecimal notation and it is equivalent to:

TEXTUREFLAGS_POINTSAMPLE = 1,
TEXTUREFLAGS_TRILINEAR = 16,

In the second method it appears that you are just increasing by one each time. This won't work when you combine flags, because the combined value could be the same as another flag (for example, 1 | 2 == 3).

You should use these values instead:

0x00000001  // == 1
0x00000002  // == 2
0x00000004  // == 4
0x00000008  // == 8
0x00000010  // == 16
0x00000020  // == 32
0x00000040  // == 64
etc...

These are the powers of two and they can be combined using bitwise-or in any way without giving collisions.

Mark Byers
Ok but it won't work if I just do one to like 20 will it? I still have to stagger the hexidecimal so they don't overwrite eachother right? Or am I not understanding how it works.
Justin Meiners
@user425756, if you don't use powers of two, you can't tell the difference between the 1 and the 2 being set, or 3 being set.
Paul Tomblin
Yeah thats what I was thinking.
Justin Meiners
+7  A: 

You need to offset the bits, otherwise there's no way to extract the individual flags. If you had flags corresponding to 1, 2, 3, & 4, and a combined value of 5, how could you tell if it was 2 & 3 or 1 & 4?

You can also do it this way, for example:

enum {
    FIRST = 1 << 0, // same as 1
    SECOND = 1 << 1, // same as 2, binary 10
    THIRD = 1 << 2, // same as 4, binary 100
    FOURTH = 1 << 3 // same as 8, binary 1000
};

Then you combine flags like so:

int flags = FIRST | THIRD | FOURTH;

And you extract them like this:

if (flags & THIRD) { ...
jtbandes
Thank you this is very straight forward you win.
Justin Meiners
*you win* - Really? If a good answer is posted I'd say **everyone** wins. And I *really* hope that FIRST, SECOND, etc. are just bad example names and not a suggestion to declare these constant once and reuse them. `x = SECOND | FOURTH` is not as readable as `x = TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_TRILINEAR`.
Mark Byers
+4  A: 

Flags like this are binary values, so you can combine 1, 2, 4, 8, 16, 32, 64, 128 in a single byte, or further powers of 2 up to 2^31 in an int. Because they're binary values, you can "or" them together, so if you "or" together 1,2,4 you end up with 7, for example. And you can extract the bit you want using "and" - so if you have an int with some flags or'ed together, and you want to see if the "4" bit is set, you can say if (flag & 4) and it will be true if the "4" bit is set.

Paul Tomblin
Thank you that makes more sense.
Justin Meiners
A: 

Think of the flags as an array of 32 bits (booleans)

To turn one of these bits on you OR it with 1 << BitIndex (where BitIndex is zero-based, so 0 - 31) To turn one off you AND it with ~(1 << BitIndex) To check if it's on or off you AND it with (1 << BitIndex)

Once you get over the difference between digital OR/AND against logical OR/AND it'll all click. Then you'll appreciate hexadecimal notation!

James