Something I find handy while programming is being able to use the bits in an integer-type variable as boolean flags. What I mean by that is, let’s say you have an INT that is 4 bytes in size. Each byte consists of 8 bits so this INT contains 32 bits in total (4 bytes * 8 bits in a byte). If we have a program that has 32 different boolean variables, wouldn’t it be more effective to store all of them in a single integer variable? This would especially be helpful when you want to keep your networking packets small. 32 booleans in 4 bytes instead of 32 bytes! Ultimately, it’s up to you to decide how to use it; I’m just here to show you how.
Now, I’m going to assume that you are already aware of how the binary number system works. If you don’t know about it, do a quick search on your favourite search engine and you will find many, many resources on the topic.
Setting up the Example
To keep the example small, we’re going to assume that the variable is simply 1 byte in size. This means that it has 8 bits. Each bit has a corresponding value which represents a power of two. Let’s see what this looks like:
1 2 |
Pos: 8 7 6 5 4 3 2 1 Vals:128 64 32 16 8 4 2 1 |
The general formula for getting the decimal value of a bit is calculated as follows:
1 2 3 4 5 6 7 8 |
[Bit Decimal Value] = 2 ^ ([Position] - 1) 1 = 2 ^ 0 2 = 2 ^ 1 4 = 2 ^ 2 8 = 2 ^ 3 ... 128 = 2 ^ 7 |
You can see from the above pattern that 2 to the power of the-position-of-the-bit-minus-one (or the “zero-based” position) will get us the decimal value that the bit represents. So the bit at position 4 has the value: 2 ^ (4 – 1) = 2 ^ 3 = 8
Checking the Bit Flags using Bitwise AND
Ok, we’ve got the bits and how to calculate them covered, but how do we use them as flags? I’m going to assume you understand how AND, OR and NOT work in binary and get to the good stuff.
To check the value of a bit flag, you can use the following formula:
1 |
2 ^ ([Position] - 1) == [Flag Variable] AND (2 ^ ([Position] - 1)) |
This may look a little daunting, but it’s really not. Say you want to check position 4 from above. You would do:
1 2 |
2 ^ (4 - 1) == [Flag Variable] AND (2 ^ (4 - 1)) 8 == [Flag Variable] AND 8 |
This works because if you AND the value 8 (i.e. the bit in position 4 is high) with another value, you will get 0 unless the other value has the same bit high as well.
Let’s jump in and take a look at how this works in binary. We’ll assume our current variable’s decimal value is 157 and we want to know if the bit at position 6 is high.
Here it is in binary:
1 2 3 4 |
Pos: 8 7 6 5 4 3 2 1 Val: 128 64 32 16 8 4 2 1 157: 1 0 0 1 1 1 0 1 |
You can see here that it’s not, but how do we figure that out? Well, if we look at the decimal value at position 6 — 2 ^ ( 6 – 1) = 32 — and then AND those together:
1 2 3 4 5 6 7 |
Pos: 8 7 6 5 4 3 2 1 Val: 128 64 32 16 8 4 2 1 157: 1 0 0 1 1 1 0 1 32: 0 0 1 0 0 0 0 0 --------------------------- AND: 0 0 0 0 0 0 0 0 |
You can see here, we get 0 after ANDing them. This means the bit at position 6 in the decimal value 157 is low (aka false, 0). Again, if you’re not sure why we get 0, there are plenty of resources online that describe how bitwise ANDing works. Just search for it. 🙂
Now, keeping in mind that the bit at position 6 is 32 in decimal, let’s change our saved flag value from 157 to 189 and see how it changes:
1 2 3 4 5 6 7 |
Pos: 8 7 6 5 4 3 2 1 Val: 128 64 32 16 8 4 2 1 189: 1 0 1 1 1 1 0 1 32: 0 0 1 0 0 0 0 0 --------------------------- AND: 0 0 1 0 0 0 0 0 |
Now, you can see that since the bit in position 6 is high with the decimal value 189, when we AND them together we get the value (in this case, 32) back!
Setting the Bit Flag High using Bitwise OR
OK, so following the same principle for checking the bit flag, if we want to turn it high, we can simply bitwise OR it with the value of the flag.
Let’s look at the example of setting the bit in position 6 high with our decimal value 157. Again, keep in mind the decimal value for the bit at position 6 is 32.
1 2 3 4 5 6 7 |
Pos: 8 7 6 5 4 3 2 1 Val: 128 64 32 16 8 4 2 1 157: 1 0 0 1 1 1 0 1 32: 0 0 1 0 0 0 0 0 --------------------------- OR: 1 0 1 1 1 1 0 1 |
Now, you’ll notice that when we OR them together we get the decimal value 189. Since the bit at position 6 is now high, our original value, 157, is increased by 32. You’ll also notice that if the bit had already been high, it would continue to be high because 1 OR 1 == 1.
Note: You may be thinking “Hey, so I can’t I just add/subtract 32 to set the bit?” This is only true if you know the bit is unset/set, respectively. For example, if you were trying to set the 6th bit high on the decimal value 189, and you added 32, you would get a totally different bit value because the 32 bit is already set. Long story short, use bitwise operators to be sure you’re doing it correctly.
Setting the Bit Flag Low using Bitwise NOT & AND
This is a little bit different (no pun intended 😀 ). To set a bit flag low, we have to NOT the value — which inverts its bits’ values — and then AND it.
Let’s have a look at this process by taking 189 and setting the 6th bit low.
1 2 3 4 5 6 7 8 9 10 11 |
Pos: 8 7 6 5 4 3 2 1 Val: 128 64 32 16 8 4 2 1 32: 0 0 1 0 0 0 0 0 ---------------------------- NOT(~): 1 1 0 1 1 1 1 1 189: 1 0 1 1 1 1 0 1 ~32: 1 1 0 1 1 1 1 1 ---------------------------- AND: 1 0 1 1 1 1 0 1 |
Looking at this, you can see the bit at position 6 is now low but all the other bits are still high where they should be. You’ll also see that if the bit at position 6 was low already, it would stay low because 0 AND 0 == 0.
Yeah, that’s nice, but how do I use it?
That’s how it works. To use this I’ll give some examples in C#.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/// <summary> /// Returns true if the bit at the given position is /// high (i.e. 1, true, etc.). /// </summary> /// <param name="currentFlagValue"/>The current value of the flag /// variable to check. Must be between 1 and 32 (inclusive). /// <param name="position"/>The bit position to check. bool CheckFlag(int currentFlagValue, int position) { if (position < 1 || position > 32) { throw new ArgumentOutOfRangeException( "Position value must be between 1 and 32 (inclusive)."); } int valueOfPosition = 2 ^ (position - 1); return (valueOfPosition & currentFlagValue) == valueOfPosition; } /// <summary> /// Sets the bit at the given position high (i.e. 1, true, etc.). /// </summary> /// <param name="currentFlagValue"/>The current value of the flag /// variable to check. Must be between 1 and 32 (inclusive). /// <param name="position"/>The bit position to be set high. int SetFlagHigh(int currentFlagValue, int position) { //Position argument check goes here... int valueOfPosition = 2 ^ (position - 1); return currentFlagValue | valueOfPosition; } /// <summary> /// Sets the bit at the given position low (i.e. 0, false, etc.). /// </summary> /// <param name="currentFlagValue"/>The current value of the flag /// variable to check. Must be between 1 and 32 (inclusive). /// <param name="position"/>The bit position to be set low. int SetFlagLow(int currentFlagValue, int position) { //Position argument check goes here... int valueOfPosition = 2 ^ (position - 1); return currentFlagValue & ~valueOfPosition; //~ means "NOT" in C# } |
That’s all for now! Drop a comment if you have any questions or suggestions.
Post Scriptum
This post was started over 5 years ago on February 26, 2009 and has been left essentially untouched since then. Without further delay, here it is! Woo hoo!
ruperthu says:
why not use an Enum type (essentially an integer under the covers) with the Flags attribute set?
ie.
then you can use bitwise and comparison to test if the flag you are interested is set…
Richard Marskell says:
Good question. This is something I started doing back in VB6 which (as far as I know) didn’t have something like that. The article is actually more about how it works than the short amount of code required to implement it.
This will also work with other integral data types (byte, short, and long), so if you’re in an environment where size matters (i.e. network), it may be better to send a byte down the tube vs an enum (int).
Also, I happened to show it in C#, but it could easily be ported to other languages that don’t have something built in already. 🙂