OK, this might be a bit off the beat and track of my normal posts, but I ad forgotten all about these little fellows and remembered them while playing with some old Win32 API’s. So, what are Bit Flags, well for want of a better description, it’s a way of storing more than one value in a variable. Now you can’t just store any old values in them but we will come to that.
The last time I used these was a fair few years ago when I was helping a friend (Matt Judge) write a MUD on Linux in CI think it was called Axia, , I know, madness… was fun though. Would love to know if this is still going, if you are out there Matt and read this, let me know :). Anyway, if I recall correctly we used them to store things like the players state, is he/she standing, walking, running, swimming etc, also for room locations, does the room have a north wall, a ceiling and so on.
So how do we use them in C# and why is there a restriction on the values we can use…?
First of all you need to know about logical bitwise operators and how they work, we are going to use them to set and test bits in a variable, this should also help explain why we can only use certain values. So what do I mean when I say we are going to set and test bits in a variable, well lest take an integer value of 8, in the bowels of your computer this number is represented by a binary value, a set of ones (1) and zeroes (0), lets see what the numbers from 0 to 10 look like in binary:
Integer Value | Binary Value |
0 | 00000000 |
1 | 00000001 |
2 | 00000010 |
3 | 00000011 |
4 | 00000100 |
5 | 00000101 |
6 | 00000110 |
7 | 00000111 |
8 | 00001000 |
9 | 00001001 |
10 |
00001010
|
If you look at a table of integer and binary like above that are only powers of 2 you can see that there is never a cross bit representation like this:
Integer Value | Binary Value |
1 | 00000000 00000000 00000000 00000001 |
2 | 00000000 00000000 00000000 00000010 |
4 | 00000000 00000000 00000000 00000100 |
8 | 00000000 00000000 00000000 00001000 |
16 | 00000000 00000000 00000000 00010000 |
32 | 00000000 00000000 00000000 00100000 |
64 | 00000000 00000000 00000000 01000000 |
128 | 00000000 00000000 00000000 10000000 |
256 | 00000000 00000000 00000001 00000000 |
512 | 00000000 00000000 00000010 00000000 |
1024 | 00000000 00000000 00000100 00000000 |
2048 | 00000000 00000000 00001000 00000000 |
4096 | 00000000 00000000 00010000 00000000 |
8192 | 00000000 00000000 00100000 00000000 |
16384 | 00000000 00000000 01000000 00000000 |
32768 | 00000000 00000000 10000000 00000000 |
65536 | 00000000 00000001 00000000 00000000 |
131072 | 00000000 00000010 00000000 00000000 |
262144 | 00000000 00000100 00000000 00000000 |
524288 | 00000000 00001000 00000000 00000000 |
1048576 | 00000000 00010000 00000000 00000000 |
2097152 | 00000000 00100000 00000000 00000000 |
4194304 | 00000000 01000000 00000000 00000000 |
8388608 | 00000000 10000000 00000000 00000000 |
16777216 | 00000001 00000000 00000000 00000000 |
33554432 | 00000010 00000000 00000000 00000000 |
67108864 | 00000100 00000000 00000000 00000000 |
134217728 | 00001000 00000000 00000000 00000000 |
268435456 | 00010000 00000000 00000000 00000000 |
536870912 | 00100000 00000000 00000000 00000000 |
1073741824 | 01000000 00000000 00000000 00000000 |
2147483648 | 10000000 00000000 00000000 00000000 |
int value2 = 2;
int value4 = 4;
int value8 = 8;
int value = 0;
value = value2 | value8;
int value4 = 4;
int value8 = 8;
int value = 0;
value = value2 | value8;
So the binary for value will look like this: 00001010 and will have the integer value of 10 (yes that’s how your computer does addition using binary!) This is what I love about bit flags, we have now got 2 values stored in one variable, value2 could represent if a weapon is equipped and value8 if it is loaded. If we call the | operator gain with the same values (value2 and value8), then there will be no change in value as the bits are already set.
But haw can we test if a value is set or not? This is done with the & (and) operator, this will test the variables bits like this:
int value2 = 2;
int value4 = 4;
int value8 = 8;
int value = 0;
value = value2 | value8;
int result = 0;
result = value & value2;
result = value & value4;
int value4 = 4;
int value8 = 8;
int value = 0;
value = value2 | value8;
int result = 0;
result = value & value2;
result = value & value4;
The first time we test if value2 is stored in value and it is so the result is populated with value2, the second time we test for value4 which is not in value so result is set to 0.
What if we want to just switch a bit on or off? For this we use the ^ (xor) operator, this will switch a bit that is set at 1 to 0 and one set at 0 to 1 effectively working like a light switch on the bit like this:
int value2 = 2;
int value4 = 4;
int value8 = 8;
int value = 0;
value ^= value2;
value ^= value2;
int value4 = 4;
int value8 = 8;
int value = 0;
value ^= value2;
value ^= value2;
The first call sets value to hold value2, the second call removes value2 from value as it is already set.
In my days of working on Axia we used C macros to do the job but here, as C# does not support them (a good thing I think) I will use functions. I have created a simple XNA project that uses the above operators which you can download here.
In the project I use an enum to represent my bit flags like this:
public enum
GunStates : int
{
Empty = 1,
Loading = 2,
Shooting = 4,
Equiped = 8,
Loaded = 16
}
{
Empty = 1,
Loading = 2,
Shooting = 4,
Equiped = 8,
Loaded = 16
}
Notice I have strong typed the enum as an int, you could use short, long, byte or what ever you need for the job you have in mind. The functions I use to set and check for states look like this:
public void
SetGunState(GunStates stateSet)
{
state ^= stateSet;
}
public bool CheckGunState(GunStates stateChk)
{
return (state & stateChk) == stateChk;
}
{
state ^= stateSet;
}
public bool CheckGunState(GunStates stateChk)
{
return (state & stateChk) == stateChk;
}
You could also take a look at bitwise shift too (shift left << and shift right >>), these shift the bits of a variable in the given direction a number of bits, so value2 << 1 would shift all the bits in value2 to the left 1 and the resulting value stored in value2 would be 4, if you reset value2 to equal 2 and did value2 << 2 values2’s bits would be shifted to the left 2 bits to the left resulting in value2 having the value of 8, you could then set value2 back to 2 by doing value2 >> 2. So, a quick off the top of my head implementation of this would be for say a GSM manager where the states are hidden, showing, shown and hiding so by using bitwise shifts you can alter the state in a linear manner.
The Audio I used in this project I got from here, this is also credited in the source code.
As ever C&C are welcome.
No comments:
Post a Comment