5,276,406 members and growing! (17,255 online)
Email Password   helpLost your password?
General Programming » Programming Tips » General     Beginner License: The Code Project Open License (CPOL)

The beginner's guide to using enum Flags

By toxcct

An article explaining the rudiments of how to deal with Flags in C++
C++, C, Windows, Visual Studio, Dev

Posted: 9 Apr 2006
Updated: 1 Mar 2007
Views: 55,715
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
67 votes for this Article.
Popularity: 6.13 Rating: 3.36 out of 5
21 votes, 31.3%
1
5 votes, 7.5%
2
6 votes, 9.0%
3
12 votes, 17.9%
4
23 votes, 34.3%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Introduction

One time I was roaming the Visual C++ forum (once again), I had to face the facts that bitwise operations, and binary in general, are rarely in beginners common sense. After having painned my fingers to write a long long answer to that innocent person, It became obvious that i had to share this obfuscated knowledge with the community through this article.

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 this article: Bit Twiddling Hacks By Sean Eron Anderson.

I'm so going to present the more complete way as I can 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
};

As we can see, these constant 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 appearing a high interrest in this, which is that each bit is used as a flag for a functionnality (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 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 presented above.
In the case of the instruction STYLE1 | STYLE3 | STYLE6, we so 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 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 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 was 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 &= ~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 ^= STYLE5;
}

Links

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

Conclusion

Well, here we are then. If you went 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 fastly fix it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

toxcct


Mvp

Toxcct is a GEII (Electrical and industrial IT ingineering) technician who felt in love with programming at the age of 10.

He started with his old little CASIO calculator (400 bytes of memory !!! enormous), then grown up with the Graph 50, 80, 100 series. His higher level in calculators programming came when he acquired his powerful TI-89. Here began the times where little toxcct started to learn C (on TI-GCC compiler).

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

Toxcct used to develop management applications mixing his languages and technologies knowledge. Currently, he's experiencing fun with Siebel in his professional working time.

Occupation: Software Developer (Senior)
Company: Accenture Technology Solutions
Location: France France

Other popular Programming Tips articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 45 (Total in Forum: 45) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralUsing the remaining 24 Bits?memberSauce!3:03 19 Apr '07  
GeneralRe: Using the remaining 24 Bits?mvptoxcct3:28 19 Apr '07  
GeneralRe: Using the remaining 24 Bits?memberSauce!3:34 19 Apr '07  
GeneralRe: Using the remaining 24 Bits?mvptoxcct3:40 19 Apr '07  
GeneralRe: Using the remaining 24 Bits?memberSauce!4:07 19 Apr '07  
GeneralRe: Using the remaining 24 Bits?mvptoxcct4:13 19 Apr '07  
GeneralNeed some Hex/Bin guru help!memberstretchcoder15:52 11 Dec '06  
GeneralRe: Need some Hex/Bin guru help!memberCPallini0:16 30 May '07  
General[Message Deleted]memberArkitechEBC4:31 5 Oct '06  
GeneralRe: Managedmembertoxcct4:32 5 Oct '06  
GeneralRe: ManagedmemberVuNic4:54 5 Oct '06  
Generali had to tell you this...membertoxcct4:59 5 Oct '06  
GeneralRe: i had to tell you this...membertoxcct6:30 5 Oct '06  
GeneralRe: Managedmembertoxcct6:34 5 Oct '06  
GeneralRe: Managedmemberbrahmma0:48 27 Oct '06  
GeneralRe: Managedmembertoxcct0:52 27 Oct '06  
GeneralBit Twiddling HacksmemberAnders Dalvander6:11 24 Apr '06  
GeneralRe: Bit Twiddling Hacksmembertoxcct22:42 25 Apr '06  
General#define XORmemberBuontempo3:01 24 Apr '06  
GeneralRe: #define XORmembertoxcct22:39 25 Apr '06  
AnswerRe: #define XORmemberBuontempo3:21 27 Apr '06  
GeneralFlag Count Formula?memberdjsdjsdjsdjs6:46 20 Apr '06  
GeneralRe: Flag Count Formula?membertoxcct22:36 20 Apr '06  
GeneralRe: Flag Count Formula?memberAlexandre Nikolov0:35 25 Apr '06