This subject is more advanced and takes time to learn, but as a programmer the knowledge of bitmasking is indispensable. It is used commonly in networking and performance critical areas of code. Another benefit is that it takes up little space.
Before we talk about bitmasking, first we must discuss bitflags.
A bitflag is a single bit of code in the smallest possible form a 1
or 0
. One byte of memory is 8 bits, which means eight 1
’s or 0
’s compressed together. By counting in binary you can set a bitflag to a on/off state. This is done arithmetically by using a base-2/power of 2/2^x
. Regardless of skill level, it is a necessary staple for every programmer to be able to count binary.
Since a integer can be a number from 0-255 and contain more than one bitflag, you can combine multiple flags together. This results in a technique programmers use called bitmasking.
To make code readability easier for this example, I’m going to focus on the 4 bits to the rightest side of a byte. These four here: 0000 0000.
Now this may look like code voodoo mumbo jumbo, but this is a very practical way to store boolean states for variables. To give you a real life example, we will use vehicles.
Note that these variables are all optional and you can have multiple ones without them being dependent on each other. For instance, it’s possible to have a car that has both a sticker and a dashcam.
But what if you added the same property twice?
Yikes! The bitflag has changed so that now our fancy_car
has morphed into having a sticker unintentionally. This is not what we want! To resolve this you need to use logic switches in your code.
Depending on the language this may be the &
|
~
operations or bit operations bit.band
bit.bor
bit.bnot
in Lua. The operation to set the bitflags we want needs to be the or
bit operation for a logic switch. Let’s try this again!
Success! Using logic switches to add bitflags together no longer causes unintended bugs.
To get a bitflags boolean state you need to check if it is set to 1
or 0
. The and
logic switch will be useful.
Here we compared the has_USB_port
flag against the bits set in our fancy_car
. Because fancy_car lacks a 0100
bitflag, it will return false when checked. This is due to the and
logic switch isolating the specific bit that is needed. This bit is checked against the bitflag, which returns false in this case.
If we use the minus operation on the variable, it will run into the same problem as before if we try to remove a bitflag twice or one that isn’t there. To resolve this we must use our logic switches again. This time it will be trickier, since we must use both the and
and not
bit operations.
Our not
bit operator inverts the bitflag we need to remove and the and
pairs the 1
’s together and anything with a 0
gets set to 0 regardless if it is paired with a 1
.
The main uses are simple:
Instead of looping through multiple booleans in a table like so:
Doing code like this is slow and inefficient! Not to mention it is very bloated!!! We want to minimize our code footprint as much as possible and have it run quickly by using a single variable to hold all the property states.
Another very good reason to use bitmasking is when you are sending packets of data over a network. The data needs to be as compressed as possible otherwise you end up with large packets that take longer to send and receive. By using bitmasking the data is crammed into the smallest possible form that makes delivery a blitz.
Every language has it’s own niche when it comes to the amount of bits stored in a variable. Make sure you are familiar with the max amount and don’t go past it. If the limit is bypassed, then the bitflags will need to be broken into smaller groups otherwise there will be a bug involving bits overflowing.
Another important thing that I encountered is number readability. This is especially important with larger bitflags as the numbers swell up and it’s easy to make mistakes. It looks like this:
Doing the first several bitflags are no problem, but once the numbers get past the 12th bit having to do the math in your head can lead to mistakes. Not to mention the code looks ugly. If you need to remove a flag from the set, it is a big pain to have to rewrite all the numbers.
A simpler way to manage this is to use 2^bitflag
.
The numbers are the same, but they are stored in a neater and compact fashion.
Not every programmer is going to be familiar with bitmasking. Don’t be surprised if you attempt to add it to a project and your fellow developers start scratching their heads in confusion. If that is the case, just refer them to this post and they can observe the benefits associated with the technique.
When using bitmasking for the first few times it may seem tough, but once accustomed, it becomes a natural programming habit just like any other tool.
ABOUT CODESYNDICATE
A 2D spess programmer on a journey (internals not provided) to code paradise.
FOLLOW TIMOTHY
GITHUB PROJECTS