12,512,130 members (57,255 online)
alternative version

218.7K views
92 bookmarked
Posted

# The Beginner's Guide to Using Enum Flags

, 10 Jan 2009 CPOL
 Rate this:
An article explaining the rudiments of how to deal with Flags in C++

## Introduction

Once I was roaming the Visual C++ forum (again), I had to face the fact that bitwise operations, and binary in general, are rarely in beginner's common sense. After having pained my fingers to write a very long answer to that innocent person, it became obvious that I had to share this obfuscated knowledge with the community through this article.

This is obviously a beginners article, but if you want to get deeper knowledge about the C/C++ bitwise operators cover, you can read the very complete article, An introduction to bitwise operators by PJ Arends. You can also go into a very complex (but effective) analysis of bit hacking with the article, Bit Twiddling Hacks By Sean Eron Anderson.

I'm going to present in the most complete way that I can about what we can do with bitwise operators, flags and all that binary stuff.

## The Facts

One of the places where we most find the use for this is certainly when a library provides a set of enumerations and when functions use `DWORD` as a flags container. Let's take for that article the example of an `enum` which defines some styles:

 ```enum { STYLE1 = 1, STYLE2 = 2, STYLE3 = 4, STYLE4 = 8, STYLE5 = 16, STYLE6 = 32, STYLE7 = 64, STYLE8 = 128 };``` OR ```enum { STYLE1 = 0x1, STYLE2 = 0x2, STYLE3 = 0x4, STYLE4 = 0x8, STYLE5 = 0x10, STYLE6 = 0x20, STYLE7 = 0x40, STYLE8 = 0x80 };```

As we can see, these constants are all powers of 2. To understand why these constants are chosen, we must go in binary representation:

```  1 -> 0b 00000000 00000000 00000000 00000001
2 -> 0b 00000000 00000000 00000000 00000010
4 -> 0b 00000000 00000000 00000000 00000100
8 -> 0b 00000000 00000000 00000000 00001000
16 -> 0b 00000000 00000000 00000000 00010000
32 -> 0b 00000000 00000000 00000000 00100000
64 -> 0b 00000000 00000000 00000000 01000000
128 -> 0b 00000000 00000000 00000000 10000000
```

Notice that for all of these values, only one `bit` is set at a time, all the others are equal to `0`. You now can see a high level of interest appearing in this, which is that each bit is used as a flag for a functionality (here, each bit represents a style). We can now imagine a way to mix the flags together in one variable, to avoid using as many booleans as we need flags. Consider the following example :

```0b 00000000 00000000 00000000 00100101

Flags of Style1, Style3 and Style6 are set
```

## The Main Operators

We face a problem now. C++ doesn't handle binary directly. We have to use `bitwise operators` instead. There are 3 atomic bitwise operators to know, presented by ascending order of priority : OR (`|`), AND (`&`) and NOT (`~`). Here are their behaviors:

``` x y   |        x y   &        x   ~
---------      ---------      -------
0 0   0        0 0   0        0   1
0 1   1        0 1   0        1   0
1 0   1        1 0   0
1 1   1        1 1   1
```

Knowing this, we can use these operators to build some mixes such as the ones presented above.
In the case of the instruction `STYLE1 | STYLE3 | STYLE6`, we `OR` the constants like this:

``` 0b 00000000 00000000 00000000 00000001     <- STYLE1
0b 00000000 00000000 00000000 00000100     <- STYLE3
0b 00000000 00000000 00000000 00100000     <- STYLE6
-----------------------------------------------
0b 00000000 00000000 00000000 00100101     <- STYLE1 | STYLE3 | STYLE6```

We can see that the bitwise `OR` operator is pretty much like the addition (+) operator. However, you have to be very careful if you wished to use + instead or |. The reason is simple: adding `1 + 1` resolves into `0` (plus one carry over `1`). You won't see any problem if all the constants are strictly different though, but I won't go deeper as it is a bad practice to use other than bitwise operators when processing binary operations.

## DWORD in Action

Commonly, such mixes stick to the `DWORD` type. However, this is not a must as we can do this with any integer types (`char`, `short`, `int`, `long`...). A `DWORD` is an unsigned 32 bits integer (like those used in the binary representations of this article). Let's imagine the case when we have such a `DWORD` constructed in a function, and passed to another in parameter. How can the called function know which bits are set, and which are not? Easy... Follow me!

Say we want to know if the bit of `STYLE8` is set in the `DWORD` passed in parameter. We must have a mask which we will call the `AND` parameter. In practice, the mask is the same as the constant we are about to test, so there's no additional code to create such a mask:

```DWORD parameter   ->   0b 00000000 00000000 00000000 00100101
STYLE8 mask       ->   0b 00000000 00000000 00000000 10000000
----------------------------------------
Bitwise AND       ->   0b 00000000 00000000 00000000 00000000     <- 0x00000000

DWORD parameter   ->   0b 00000000 00000000 00000000 10100101
STYLE8 mask       ->   0b 00000000 00000000 00000000 10000000
----------------------------------------
Bitwise AND       ->   0b 00000000 00000000 00000000 10000000     <- STYLE8
```

If the `AND` operation returns `0`, then, the bits were not set, otherwise, you get the mask you applied.

OK, now, in practice, here is how you'll often see it:

```void SetStyles(DWORD dwStyles) {
if ((STYLE1 & dwStyles) == STYLE1) {
//Apply style 1
}
else if ((STYLE2 & dwStyles) == STYLE2) {
//Apply style 2
}
else if ((STYLE3 & dwStyles) == STYLE3) {
//Apply style 3
}
//etc...
}```

I didn't present the third operator NOT (`~`) yet. It is generally used when you have a set of bits, in which some are set and some aren't, and where you'd like to remove one of them. The sample of code below exposes how this can be done:

```void RemoveStyle5 (DWORD& dwStyles) {
if ((STYLE5 & dwStyles) == STYLE5) {
dwStyles = dwStyles & ~STYLE5;
}
}```

I didn't mention the XOR ( `^` ) operator yet. The reason why it comes last is for the only reason that this operator is not atomic; that means that we can reproduce its behavior with the other operators presented already:

`#define XOR(a,b) (((a) & ~(b)) | ((b) & ~(a)))`

Anyway, this operator can be used to easily switch one bit :

```void SwitchStyle5 (DWORD& dwStyles) {
dwStyles = dwStyles ^ STYLE5;
}```

## The Other Operators

Now, to perfect your sharpen skills on bits handling, there are few other operators you have to know to be unbeatable: the shift operators. Those can be recognized like this : `<<` (left shifting, follow the arrows), `>>` (guess what, this is a right shifting).

What a shifting operator is moving the bits of n positions to the right or to the left. The "space" made by the movement is padded with zeros, and the bits pushed over the limit of the memory area are lost.

Let's take an example:

```BYTE dwStyle = STYLE1 | STYLE3 | STYLE6;    //    [00100101]000
<-
dwStyle = dwStyle << 3;                     // <s>001</s>[00101000]

BYTE dwStyle = STYLE1 | STYLE3 | STYLE6;    // 000[00100101]
->
dwStyle = dwStyle >> 3;                     //    [00000100]<s>101</s>```

"But" I hear you say, "what is that for" ?". Well, there are tons of applications which I don't particularly have in mind right now, but trust me, when you need it, be happy it's there.

Anyway, two funny uses of such operators I can think of is the division and the multiplication of an integer by 2. Check this:

```char i = 127;    // 0b01111111 ( = 127)
i = i >> 1;      // 0b00111111 ( = 63)
i = i << 1;      // 0b01111110 ( = 126)```

Shifting one bit right, then one bit left gives a different result from the beginning. That's because as we just saw, the "overflown" bits are lost, and the newly inserted ones are set to 0. But let's look closer. This is working anyway because we are working on integers. That is, dividing an odd number will not give a float (we don't care about the remaining 0.5).

Here, `127 / 2` should be `63.5`, so it gives `63`, due to the truncation.
`63 * 2 = 126`, isn't it what we want ?! :-)

Now we've seen all the useful operators, just know that all of them have their own assignment operator.

```dwStyle  &= 0x2     -->     dwStyle = dwStyle &  0x2
dwStyle  |= 0x2     -->     dwStyle = dwStyle |  0x2
dwStyle  ^= 0x2     -->     dwStyle = dwStyle ^  0x2
dwStyle <<= 0x2     -->     dwStyle = dwStyle << 0x2
dwStyle >>= 0x2     -->     dwStyle = dwStyle >> 0x2```

## A Funny Example

Thanks to Randor in the VC++ forum, here is a nice example of what is possible to do with such operators (Credit for the discovery of this little neat trick below goes to Sean Anderson at stanford university).

"How is it possible to reverse the bits of an integer, say from 11010001 to 10001011 ?"

```BYTE b = 139;  // 0b10001011
b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;```

"Wowwww, how is this working man ?!"

```DWORD iTmp = 0;
BYTE b = 139;               // 00000000 00000000 00000000 10001011
DWORD c = (b * 0x0802LU);   // 00000000 00000100 01011001 00010110
c &= 0x22110LU;             // 00000000 00000000 00000001 00010000
DWORD d = (b * 0x8020LU);   // 00000000 01000101 10010001 01100000
d &= 0x88440LU;             // 00000000 00000000 10000000 01000000
iTmp = (c | d);             // 00000000 00000000 10000001 01010000
iTmp = iTmp * 0x10101LU;    // 10000001 11010001 11010001 01010000
iTmp >>= 16;                // 00000000 00000000 10000001 11010001
b = iTmp;                   // 00000000 00000000 00000000 11010001```

## Conclusion

Well, here we are then. If you came here to understand these binary operations, I hope that I helped you in your way. If you came to see what was going on here, then don't hesitate to point my mistakes if any, so that I can fix them.

The following links are for complimentary knowledge, if you like to go deeper in bitwise handling:

## Share

 Software Developer (Senior) Accenture Technology Solutions France

Toxcct is an electronics guy who felt in love with programming at the age of 10 when he discovered C to play with Texas-Instruments calculators.

Few years later, he discovered "The C++ Language" from Bjarne Stroustrup ; a true transformation in his life.

Now, toxcct is experiencing the Web by developing Siebel CRM Applications for a living. He also respects very much the Web Standards (YES, a HTML/CSS code MUST validate !), and plays around with HTML/CSS/Javascript/Ajax/PHP and such.

_____

After four years of services as a Codeproject MVP, toxcct is now taking some distance as he doesn't like how things are going on the forums. he particularly doesn't accept how some totally ignorant people got the MVP Reward by only being arrogant and insulting while replying on the technical forums.

## You may also be interested in...

 Pro Pro

 First Prev Next
 packing dates using 32 bits hcraes11-Jan-09 8:04 hcraes 11-Jan-09 8:04
 Re: packing dates using 32 bits toxcct11-Jan-09 10:46 toxcct 11-Jan-09 10:46
 Using the remaining 24 Bits? Sauce!19-Apr-07 2:03 Sauce! 19-Apr-07 2:03
 Re: Using the remaining 24 Bits? toxcct19-Apr-07 2:28 toxcct 19-Apr-07 2:28
 Re: Using the remaining 24 Bits? Sauce!19-Apr-07 2:34 Sauce! 19-Apr-07 2:34
 Re: Using the remaining 24 Bits? toxcct19-Apr-07 2:40 toxcct 19-Apr-07 2:40
 Re: Using the remaining 24 Bits? Sauce!19-Apr-07 3:07 Sauce! 19-Apr-07 3:07
 Re: Using the remaining 24 Bits? toxcct19-Apr-07 3:13 toxcct 19-Apr-07 3:13
 Need some Hex/Bin guru help! stretchcoder11-Dec-06 14:52 stretchcoder 11-Dec-06 14:52
 Re: Need some Hex/Bin guru help! CPallini29-May-07 23:16 CPallini 29-May-07 23:16
 [Message Deleted] ArkitechEBC5-Oct-06 3:31 ArkitechEBC 5-Oct-06 3:31
 Re: Managed toxcct5-Oct-06 3:32 toxcct 5-Oct-06 3:32
 Re: Managed VuNic5-Oct-06 3:54 VuNic 5-Oct-06 3:54
 i had to tell you this... toxcct5-Oct-06 3:59 toxcct 5-Oct-06 3:59
 Re: i had to tell you this... toxcct5-Oct-06 5:30 toxcct 5-Oct-06 5:30
 Re: Managed toxcct5-Oct-06 5:34 toxcct 5-Oct-06 5:34
 Re: Managed brahmma26-Oct-06 23:48 brahmma 26-Oct-06 23:48
 Re: Managed toxcct26-Oct-06 23:52 toxcct 26-Oct-06 23:52
 Bit Twiddling Hacks Anders Dalvander24-Apr-06 5:11 Anders Dalvander 24-Apr-06 5:11
 Re: Bit Twiddling Hacks toxcct25-Apr-06 21:42 toxcct 25-Apr-06 21:42
 #define XOR Buontempo24-Apr-06 2:01 Buontempo 24-Apr-06 2:01
 Re: #define XOR toxcct25-Apr-06 21:39 toxcct 25-Apr-06 21:39
 Re: #define XOR Buontempo27-Apr-06 2:21 Buontempo 27-Apr-06 2:21
 Most common fundamental underlying operator is NAND supercat910-Jan-09 13:46 supercat9 10-Jan-09 13:46
 Everything can be synthesized from the NAND operator; all but one of the dyadic (two-operand) operators may be synthesized from four or fewer NANDs. XNOR requires five. The NOR operator may be substituted for NAND. When using NOR, XNOR takes four NORs and XOR takes five. A couple alternatives which I've not seen used much in electronics would be (A and not B), or else (A or not B). I'm surprised I haven't seen 7400-series chips to implement those; they are seldom optimal, but are often better than NANDs. Function/NANDs/NORs/(A and not B) (A or not B) AND/2/3/2/3 OR/3/2/3/2 NAND/1/4/3/2 NOR/4/1/2/3 A~B/3/2/1/2 A+~B/2/3/2/1 XOR/4/5/3/4 XNOR/5/4/4/3
 Flag Count Formula? djsdjsdjsdjs20-Apr-06 5:46 djsdjsdjsdjs 20-Apr-06 5:46
 Re: Flag Count Formula? toxcct20-Apr-06 21:36 toxcct 20-Apr-06 21:36
 Re: Flag Count Formula? Alexandre Nikolov24-Apr-06 23:35 Alexandre Nikolov 24-Apr-06 23:35
 Re: Flag Count Formula? ABuenger25-Apr-06 1:05 ABuenger 25-Apr-06 1:05
 Re: Flag Count Formula? Alexandre Nikolov25-Apr-06 1:20 Alexandre Nikolov 25-Apr-06 1:20
 Re: Flag Count Formula? toxcct25-Apr-06 21:34 toxcct 25-Apr-06 21:34
 Re: Flag Count Formula? CPallini18-Dec-07 4:05 CPallini 18-Dec-07 4:05
 Re: Flag Count Formula? Member 375083412-Jan-09 21:14 Member 3750834 12-Jan-09 21:14
 Good article, but... Steve Folly11-Apr-06 20:04 Steve Folly 11-Apr-06 20:04
 Re: Good article, but... toxcct11-Apr-06 21:47 toxcct 11-Apr-06 21:47
 An alternative definition... Jun Du10-Apr-06 9:01 Jun Du 10-Apr-06 9:01
 Re: An alternative definition... v2.010-Apr-06 21:30 v2.0 10-Apr-06 21:30
 Re: An alternative definition... Pravin Wagh11-Apr-06 0:16 Pravin Wagh 11-Apr-06 0:16
 Re: An alternative definition... John M. Drescher13-Apr-06 4:20 John M. Drescher 13-Apr-06 4:20
 Re: An alternative definition... (simpler) Robert Bielik11-Apr-06 9:34 Robert Bielik 11-Apr-06 9:34
 Re: An alternative definition... (simpler) Roland Pibinger24-Apr-06 10:11 Roland Pibinger 24-Apr-06 10:11
 Re: An alternative definition... manos5-Mar-07 21:12 manos 5-Mar-07 21:12
 Nice, a few things... ricecake10-Apr-06 4:18 ricecake 10-Apr-06 4:18
 Re: Nice, a few things... toxcct10-Apr-06 4:27 toxcct 10-Apr-06 4:27
 Re: Nice, a few things... JHS10-Apr-06 9:23 JHS 10-Apr-06 9:23
 Re: Nice, a few things... Daniel Fruzynski17-Apr-06 23:13 Daniel Fruzynski 17-Apr-06 23:13
 Really Cool click.ok10-Apr-06 2:18 click.ok 10-Apr-06 2:18
 Re: Really Cool toxcct10-Apr-06 4:30 toxcct 10-Apr-06 4:30
 [Message Deleted] ddmcr10-Apr-06 0:22 ddmcr 10-Apr-06 0:22
 Re: Nice toxcct10-Apr-06 0:35 toxcct 10-Apr-06 0:35
 Last Visit: 31-Dec-99 18:00     Last Update: 1-Oct-16 4:18 Refresh 1