Bitflags and you: A FreeBASIC/QBASIC tutorial
By Imortis Inglorian (Luther Ramsey)
Hello, class. My name is Mr. Inglorian and today we will be learning about a very special type of variable called a flag. Now, some of you may know exactly what I am talking about and may think that this tutorial is a waste of time... Well, you know what... *sniffle* I DON'T LIKE YOU ANY MORE! DON'T LOOK AT ME!
Seriously though, this is something that many people may not understand, so I figured a thorough tutorial would be good.
Let's Get Started:
What is a flag, you ask? A flag is any variable in which the values have a very specific significance. That value could be anything. Just so long as it has some significance to the program. Traditionally, flags are either yes/no, true/false, or 0/1. For those of you who have used newer languages, boolean variables are flags. A flag could just as easily be any other value. When I was in a beginning programming class, we would often use the number 9999 as a flag, or even the word “done”. The point here is that it does not matter what the flag value is, just that it is important to the program in some way. For this tutorial we will be talking about a special type of flag called a bit flag. This i s where you use a single bit for a flag. That means that you are working with the 0/1 type of flag because that is the only numbers that can be represented by a bit.
Now, when using bits, you have some very interesting problems. One of which is counting. For those of you who know how to count in binary, you may wish to skip this section.
For those of you left, let's get started. Most of us are used to base 10 number systems. That is, decimal. We understand the number 128 or 1,024 at a glance. We have no problem deciphering that. But if we have the number &b10000000, or perhaps &b10000000000, the mind goes in a completely different direction. These numbers are, in fact, decimal 128 and 1,024, just represented in base 2 instead of base 10. Base 10 has a 1's column, a 10's column, a 100's column, and so on. Base 2 and a 1's column, a 2's column, a 4's column, a 8's column, a 16's column, a 32's column, and so on. If you look at base 10, every place value goes up by an order of 10, that is, add a zero to the end. In base 2, every place value goes up double the one before it. This may seem confusing, but it works just the same as decimal. When you count in decimal you have 10 digits to work with: 0-9. You start out like this:
What happens when you run out of digits? You start a new column out with 1, then keep going:
Now what do you do? You ran out of digits with the right column again... Well, now you increment the first column again:
And so on. It is no different with binary. The only difference is that it only has two digits to work with. Instead of 0-9, you only have 0 and 1 so it looks like this:
Oh, we ran out... Time to make a new column and start it at 1:
Dang, ran out again... New Column:
Now what? We ran out in the first column, so we reset it to zero and move up to the next:
And so on. It's just like decimal, only with fewer digits.
I Told You That To Tell You This:
Now that you (hopefully) understand binary, we can look at the rest of the topic. Lets look at a complex looking binary number:
This is decimal 172, but that's not important right now. What is important is what the number is made up of. It is made up of 8 individual flags. 8 ones or zeros. From those eight digits you can have 256 possible combinations of numbers. Do you realize that you can use those 8 digits to store the answer to 8 different yes/no style questions? It's true! And that is what I am going to show you how to do in this tutorial: To store and retrieve information from bitflags in any variable you like.
Use of Bitflags:
Imagine you are making a game. Your player can do all sorts of thing in your game. He can jump, attack, fall, get hit, and die. Now imaging trying to keep track of all those pieces of information:
Dim as String isJumping Dim as String isAttacking Dim as String isFalling Dim as String isHit Dim as String isDead If isJumping = “Yes” then 'Do some code related to jumping ElseIf isAttacking = “Yes” then 'Do some code related to attacking ElseIf ... EndIf
And thats just a small sample! What if you wanted the player to be able to attack while jumping? What if you wanted the player to be able to crawl? Or fly? You would have to make a new string variable for each possible state, and check if it is “Yes” or “No” on every single turn. That is a lot of strings! In QB you have some memory limitations, and strings can bet pretty costly. Plus, strings take more time for the computer to work with, so you can slow down your program considerably in that manor in both QB and FB. A better way to handle it is to use a number:
Dim as Integer isJumping Dim as Integer isAttacking Dim as Integer isFalling Dim as Integer isHit Dim as Integer isDead If isJumping = 1 then 'Do some code related to jumping ElseIf isAttacking = 1 then 'Do some code related to attacking ElseIf ... EndIf
This is much more efficient in terms of memory and speed, but still not great. With bitflags you can store all those question variables in one variable.
Dim as Integer PlayerFlags
This one variable can hold 16 questions in QB and 32 in FB. Nice huh? Talk about conserving memory. Now let me show you how it is done:
How It's Done:
First thing you do is use ANDing. You use the AND keyword in FB or QB to accomplish this task. ANDing will only return 1 if both pieces it looks at are 1. So here is what is called a Truth Table for AND:
0 AND 1 = 0 1 AND 0 = 0 0 AND 0 = 0 1 AND 1 = 1
Understand? That means that every time AND finds a 1 in both of your binary numbers, it will return a 1 in its output. Here is a more complex example:
10101100 AND 10010100
I'm going to put them one over the other so you can see the results more clearly.
10101100 10010100 ------------ 10000100
The only time a 1 came through is when both numbers had a one in the same column. This is the process of ANDing. So, if you want to see if the 3rd bit is currently a 1, you just do this:
10101100 – Number to check for third bit 00000100 – Just the third bit active ----------- 00000100 – Result will be just the third bit set.
If the result comes out as the bit you were looking for, then the bit was set. If it comes out as 0, then the bit was not set in the number you checked for. See? Easy, right? In code you can check it like this:
If ([bitflag] and [desired bit]) = [desired bit] then ‘Do code if bit is set EndIf
Now you know how to see if a bit was set. Next, I’ll show you have to set a bit. Setting a bit is done through ORing. OR returns 1 if either the first number or the second number has a one in that column. Here is a truth table for OR:
0 OR 1 = 1 1 OR 0 = 1 0 OR 0 = 0 1 OR 1 = 1
Using the numbers I used earlier, that would look like this:
10101100 10010100 ------------ 10111100
The result is that everywhere there is a one in either number, the result will be a one. So if you want to set the fifth bit in a number you just OR then number with the bit you are looking for. Like this:
10101100 – Original Number 00010000 – fifth bit ----------- 10111100 – Result will be original number with fifth bit set.
Nice huh? And here is the code for doing it:
[bitflag] = [bitflag] OR [desired bit]
See? It’s that simple. Now, that’s all fine and good, but what if you want to set a bit to zero? OR won’t work for that. Instead you need to use AND and NOT. NOT takes every 1 bit and changes it to 0, and every 0 bit gets changed to 1. NOT just switches all bits to the opposite digit. Here is a truth table for NOT:
NOT 1 = 0 NOT 0 = 1
So if you were to use NOT on the Number we have been using, it would look like this:
10101100 – This is the original number ----------- 01010011 – The is the result
So to set bit 4 to 0, you need to do this:
10101100 – Original Number 11110111 – All but fourth Bit set (result of NOT on fourth bit alone) ---------- 10100100 – The only thing changed was the fourth bit. It is now off.
See. That’s simple too. The code for that looks like this:
[bitflag] = [bitflag] AND NOT([desired bit])
See. It’s easy. The cool part is that this code will work in FB or QB, with no changes between them. You can use the same code in both and it will work perfectly. But if you don’t like doing all that in FB it does have a few macros that you can use to make it a little less painful.
BIT works like ANDing to find out if a bit is 1 (set). The difference is that you don’t need to pass it the number that evaluates out to just that bit being set. Instead you just pass to it the number of that bit. So if you want to know if the fourth bit is set, you do this:
Result = BIT([original numbet], 4)
If the fourth bit is set, then it will return 1, otherwise it returns 0.
BITSET sets the bit you request. Its usage is just like BIT, so I won’t go into a long explanation. Instead, I’ll just show you:
Result = BITSET([original number], [number for desired bit])
The result is the original number with the bit you requested set.
BITRESET looks just like BITSET, only it sets the desired bit to 0:
Result = BITRESET([original number], [number for desired bit])
The result will be the original number with the requested bit being set to 0 (or reset).
So, there you have it. This is a simple and memory-efficient way to do a boolean style variable in FB or QB. You can do all kinds of neat stuff with it, but I will leave that for another tutorial if anybody wants one. Here is a source code file that demonstrates what I just showed you. Let me know by e-mailing me at ImortisInglorian@gmail.comImortisInglorian@gmail.com.