www.programmingmoney.com How to program Enum Bit Flags 1 How to Program Enum Bit Flags When I started programming, I thought that I was the best. I would program if else statements and nested for loops. The complexity of programming was amazing. Seeing giant spikes of doom appear to the left of my programming environment was really cool as well. Then I learned about enum bit flags. This is my lesson to you, for those interested in programming enum bit flags. Enum variables are the bomb. Bit Flags are too. When combined, they become very powerful. By the end of this, you will learn everything that I know about using enums in C++ to their fullest. Without Bit Flags What happens if we want enumerations to be intelligent? For example, a human understands why mixing paint causes colors to change. Mixing blue and yellow paint together makes green paint. A computer does not know that, unless we program it. This is important, because if we have a program that asked the user to enter his or her favorite color, we could provide more than just a basic a response. With enum bit flags, which use bitwise operations, we can tell the user if he or she entered a primary color, its mixed contents, and more. Shown below, is how one would write a function to determine if a given color is a primary color. IsPrimary(Colors color) return (color == C_BLUE color == C_RED color == C_YELLOW) This is cool, but can we add just create another enum variable called IS_PRIMARY_COLOR? Also, we could have a variable ORANGE_PAINT_CONTENTS, and even ORANGE_LIGHT_CONTENTS. In order to do this, we need to change our enum a little bit.
www.programmingmoney.com How to program Enum Bit Flags 2 Power of Two The first change which must be made, is to have Colors equal to a power of two. This will make each number s binary value have a bunch of 0 s, and only one 1. As a result, each variable will have a 1 in a different digits place. That means, we can assign other values with more binary 1's. This is how we make our enums intelligent, and this is what a bit flag is. Also, C_NONE was changed to 0, because we may want to check set a color be empty, like and empty paint bucket, or a light that is turned off. C_NULL, which was added is -1, which would me no paint bucket, or no light switch. //Binary value C_NULL =-1, C_NONE = 0, 00000000 C_RED = 1, 00000001 C_BLUE = 2, 00000010 C_YELLOW = 4, 00000100 C_GREEN = 8, 00001000 NUMBER_COLORS = 5 //This must be manually figured out. ; Enum Bit Flags Using the bitwise OR ' ', we can set enum variables to equal multiple values at the same time. As a result, we eliminate the need for if-else and switch style functions. In addition, our colors become intelligent. In addition, removing the need to create function, removes the hassle of adding extra function declaration in their corresponding header files and its implementation in the cpp file. //Binary value C_NULL = -1, //(i.e. no paint bucket, or no light switch) C_NONE = 0, //(i.e. empty paint bucket, or light switch set to off) C_RED = 1,
www.programmingmoney.com How to program Enum Bit Flags 3 C_BLUE = 2, C_YELLOW = 4, C_GREEN = 8, C_ORANGE = 16, C_PURPLE = 32, NUMBER_COLORS = 7, // //OR //OR //OR //OR //OR IS_PRIMARY_PAINT_COLOR = (C_RED C_BLUE C_YELLOW), //00000111 IS_PRIMARY_LIGHT_COLOR = (C_RED C_BLUE C_GREEN), //00001011 IS_SECONDARY_PAINT_COLOR = (C_GREEN C_ORANGE C_PURPLE), ORANGE_PAINT_CONTENTS = (C_RED C_YELLOW), YELLOW_LIGHT_CONTENTS = (C_GREEN C_RED), ; Are we done yet? Not yet. There is still a better way to implement out bit flags. For example, what happens if we have 100000 enum variables? Trying to calculate each and every enum value to the next power of two is unreasonable. Shifting Bits With a few simple changes, power of two calculations become super easy. The #define macro Fl(n), inserts a bit 1 at a given bit value. As a result, it calculates the power of two for us. Also, since enums are constant, and initialized at compile time, they cannot be assigned via a function call. The macro inserts the equation into the enum at compile time. The code shown below has the macro, and is implemented into the enumeration, Colors. Also, I have commented to the right of each line, what exactly is happening behind the scenes of the compiler. #define Fl(n) (1 << (n)) //Binary value C_NULL = -1, C_NONE = Fl(0), //1 << (0) == 00000000 == 0 C_RED = Fl(1), //1 << (1) == 00000001 == 1 C_BLUE = Fl(2), //1 << (2) == 00000010 == 2 C_YELLOW = Fl(3), //1 << (3) == 00000100 == 4 C_GREEN = Fl(4), //1 << (4) == 00001000 == 8 C_ORANGE = Fl(5), //1 << (5) == 00010000 == 16 C_PURPLE = Fl(6), //1 << (6) == 00100000 == 32 NUMBER_COLORS = 7 //<-- You know that last was 6, NUMBER_COLORS must be 7 IS_PRIMARY_PAINT_COLOR = (C_RED C_BLUE C_YELLOW), IS_PRIMARY_LIGHT_COLOR = (C_RED C_BLUE C_GREEN), IS_SECONDARY_PAINT_COLOR = (C_GREEN C_ORANGE C_PURPLE), ORANGE_PAINT_CONTENTS = (C_RED C_YELLOW), YELLOW_LIGHT_CONTENTS = (C_GREEN C_RED), ; Accessing Enum Bit Flags It seems as if there is always a better way of programming variables. As with enum bit flags, the ability to access them is important too. Since we are using an array to store constants, as explained in the previous post, we need a way to access the proper index of the array, using our
www.programmingmoney.com How to program Enum Bit Flags 4 power of two enums. We can loop through the array using number of colors, and return the power of two. The opposite applies too. We can loop through Colors, and return the text from the corresponding array index. string ColorNames[NUMBER_COLORS] = "none", "red","blue","yellow", "green", "orange", purple"; Colors GetColor(string input) if(colornames[i] == input) return (Colors)Fl(i); return C_NULL; string GetColorName(Colors color) //Check if the color is a color, and not an intelligent operation if((int)color < Fl(NUMBER_COLORS)) if(color == Fl(i)) return ColorNames[i]; return "ERROR: Color does not exists"; return "ERROR: Not a vaild paramater value"; (Shown above) The first function, returns the, based on a given string. The second function returns a string, based on a given Color. These were adjusted to the now implemented bit flags. Enum Bit Flag Operations This is the final part. What happens if we want to check for something specific Like if a color is RED inside of an if statement? We need to use bit operators instead of regular logical operators. We can do that too. To check if an enum is equal to another enum, we use the bitwise operation = ; if(c_red = IS_PRIMARY_PAINT_COLOR) true //Bit flags, compared using = C_RED = 00000001 IS_PRIMARY_PAINT_COLOR = 00000111 RESULT: = 00000111 //At least one bit must equal C_RED
www.programmingmoney.com How to program Enum Bit Flags 5 An example of when this would be important, is checking if the color that the use entered is both a primary color for both light and paint. We can write add the following code as a function bool IsColorDualPrimary(Colors color) //Method One: check bit values of each Colors enum return ((color = IS_PRIMARY_PAINT_COLOR) && (color = IS_PRIMARY_LIGHT_COLOR)); //Method Two: do a AND bit operation, and beck the enum against the result return (color = (IS_PRIMARY_PAINT_COLOR & IS_PRIMARY_LIGHT_COLOR)); //Method three: add the following code to the enum. I personally like method two better. //That is because long variable names can get really annoying IS_PRIMARY_PAINT_AND_LIGHT_COLOR = (IS_PRIMARY_PAINT_COLOR & IS_PRIMARY_LIGHT_COLOR); Separate Enum Flags Guess what, there is another way to improve our code. In the case where we have only a few Colors, and 1000 Flags, what happens to Colors? Does it represent the different colors on the visible spectrum, or does it represent a bunch of information relating to the colors? It would be best to put all of the enum flags in its own enumeration. This will also let the programming know that its contents are for bit flag operations. The data, and the operations should be separate. To do this, we make a new enum, and add _FLAGS to it. Also we change the prefix to CF_ for Color Flags. #define Fl(n) (1 << (n)) C_NULL = -1, C_NONE = Fl(0), C_RED = Fl(1), C_BLUE = Fl(2), C_YELLOW = Fl(3), C_GREEN = Fl(4), C_ORANGE = Fl(5), C_PURPLE = Fl(6), NUMBER_COLORS = 7 //<-- You know that last was 6, NUMBER_COLORS must be 7 ; enum ColorFlags CF_PRIMARY_PAINT_COLOR = (C_RED C_BLUE C_YELLOW),
www.programmingmoney.com How to program Enum Bit Flags 6 CF_PRIMARY_LIGHT_COLOR = (C_RED C_BLUE C_GREEN), CF_SECONDARY_PAINT_COLOR = (C_GREEN C_ORANGE C_PURPLE), CF_ORANGE_PAINT_CONTENTS = (C_RED C_YELLOW), CF_YELLOW_LIGHT_CONTENTS = (C_GREEN C_RED), ; Congratulations That is it. You are now are advanced at programming enum bit flags in C++. Here is the code: #include <string> #define Fl(n) (1 << (n)) C_NULL = -1, C_NONE = Fl(0), C_RED = Fl(1), C_BLUE = Fl(2), C_YELLOW = Fl(3), C_GREEN = Fl(4), C_ORANGE = Fl(5), C_PURPLE = Fl(6), NUMBER_COLORS = 7 //<-- You know that last was 6, NUMBER_COLORS must be 7 ; string ColorNames[NUMBER_COLORS] = "none", "red","blue","yellow", "green", "orange", purple"; enum ColorFlags CF_PRIMARY_PAINT_COLOR = (C_RED C_BLUE C_YELLOW), CF_PRIMARY_LIGHT_COLOR = (C_RED C_BLUE C_GREEN), CF_PRIMARY_PAINT_AND_LIGHT_COLOR = (IS_PRIMARY_PAINT_COLOR & IS_PRIMARY_LIGHT_COLOR); CF_SECONDARY_PAINT_COLOR = (C_GREEN C_ORANGE C_PURPLE), CF_ORANGE_PAINT_CONTENTS = (C_RED C_YELLOW), CF_YELLOW_LIGHT_CONTENTS = (C_GREEN C_RED), ; Colors GetColor(string input) if(colornames[i] == input) return (Colors)Fl(i); return C_NULL; string GetColorName(Colors color) //Check if the color is a color, and not an intelligent operation if((int)color < Fl(NUMBER_COLORS)) if(color == Fl(i))
www.programmingmoney.com How to program Enum Bit Flags 7 return ColorNames[i]; return "ERROR: Color does not exists"; return "ERROR: Not a valid parameter value"; Readers Challenge Alright, this is something I am starting to do. For this post, I challenge you to research how and when to use the AND, and XOR Operator. In addition, create the main function that revived use input, and displays the information about the color, using precalculated enum big flags.