Sunday, January 19, 2014

Simple Introduction to Bit Masking

Hello everyone, I'm back online after a long while. Meaning, it's back to learning! Now, that's not to say that I have learned quite a fair bit during my 6 months without easy internet access, I downloaded various articles and read them at home. But now that I have internet access at my finger tips, I can begin researching a lot more in depth.

Anyway, in celebration of my return I'm going to actually talk about a quite simple topic, but one which is very useful in programming in general. I know, I said I would talk about state management and such, but plans have changed. I also plan on giving this site a minor upgrade to look better and hopefully I will start making some regular (meaningful) posts.

The topic today, is bit masking. Bit masking is the process of accessing one bit, in a series of one or more bytes. This is done by creating what is called a "bit mask" which "points" (not as in using pointers, this will be explained soon) to the bit of interest. Then, using bit-wise operators, we can read/set that bit in the target object (which is normally a char or int).

A bit mask is often the same size as the target object. This means if you want to access a bit in an integer, you would create another integer and "point" it at that specific bit. "Pointing" is done by assigning a value that contains only one bit in it that is set to '1'. Examples of this are:

char mask = 0x80 // One byte value of 1000 0000.

char mask = 0x40 // One byte value of 0100 0000.

char mask = 0x02 // One byte value of 0000 0010.


Notice how each one of these hex values produces a result with only one '1' in the value. This is essential, as the '1' is in the same position in this object, as the target object's bit we want to read/set.

In order to use this bit mask for reading/setting the bit in the target object, you would use a bit-wise operator, as mentioned before. The bit-wise operators are & (AND), | (OR) and ~ (NOT). The & operator is used for reading the bit and the | and ~ operators are used for setting the bit to '1' or '0'.

In case you are unaware, the & operator will check the bits in two objects and return a value containing '1's where both bits in a single position were '1' and the | operator will return a value containing '1's where either of the bits in a single position were '1'. The ~ operator on the other hand is a tad different, it only works with a single value and will return a value that reverses the '1's and '0's in it. For example:

char val = 0x26; // 0010 0110

char valtwo = 0x3A; // 0011 1010



val & char // Returned value is 0010 0010.

val | char // Returned value is 0011 1110.

~val // Returned value is 1101 1001.

~valtwo // Returned value is 1100 0101.


The following three functions will handle reading, setting and clearing the bit pointed to by the mask passed in the target object passed:

bool readBit(const unsigned char &byte, const unsigned char &mask) {

    return (mask & byte) ? 1 : 0; // If the bit pointed at is '1', return '1', else return '0'.

}



void setBit(unsigned char &byte, const unsigned char &mask) {

    byte |= mask; // Only changes the bit pointed at by mask, sets it to '1'.

}



void clearBit(unsigned char &byte, const unsigned char &mask) {

    byte &= (~mask); // Only changes the bit pointed at by mask, sets it to '0'.

}


If these functions don't quite make sense, I recommend drawing it out on paper. If that doesn't do the trick leave a comment or send me a message and I'll help you out.

The more advanced readers may have noticed something, it is possible to have the mask point at more than one bit. A mask of the value 0x82 (1000 0010) could be used to return true with readBit() if any of the bits pointed to are '1', or it could be used to setBit()/clearBit() the bits pointed to as '0' or '1'.

As a side note, this is how flags work for functions you find in libraries such as SDL, where the SDL_Init() function takes flags that can be | (OR'd) together to set up different sub-systems. In this case the mask is of unsigned int type and each of the possible flags you can pass (SDL_VIDEO, SDL_AUDIO, etc.) have their own special bit-mask (0x00000008 for example) that is used. The functions we created, also support this use.

I hope you have learned something from this article, next time I will most likely cover how to use bit masking to accomplish bit-by-bit file I/O, a useful feature for reading and writing large map files and plugins.

This was a fun article to write and I hope it shows that I am indeed trying to provide more cognitive articles that are of better use to new game programmers. My old articles were a quite under-developed and did not get the point across in as well (or as polished) a way as I would prefer. Leave a comment if you have any questions, ideas for future articles or even something to add on to this one to make it better.

Until next time - Torben Carrington.