If you’ve used any legacy C libraries before, you’ve probably used these things called bit fields, even if you didn’t know what they were.
Bit fields are a way to efficiently store multiple boolean values in one or more bytes. If you can imagine an 8 bit integer as binary, each bit would have to be either a 1 or a 0, corresponding to an “On” or “Off” value. With just one 8 bit variable, you can store 8 on/off values for your program. The syntax on how to set, unset, and retrieve these values can be a little confusing however. The method for using these helpful little bit fields involves some binary math with the binary operators AND, OR, and NOT. In C based languages these are written as &, |, and, ~, respectively. I’ll give an example in C that will hopefully make this math clearer. First we need to define some values as our flags. Each flag has to have a value that is a power of 2. For example:
enum FLAGS { FLAG_A = 0x01,// 1 FLAG_B = 0X02,// 2 FLAG_C = 0X04,// 4 FLAG_D = 0X08,// 8 FLAG_E = 0X10,// 16 FLAG_F = 0X20 // 32 // so on and so forth };
These could just as easily be written as the actual integer values, however I’ll stick to HEX notation for this example. Next we need a variable of at least 6 bits to hold our flags’ on or off state. Let’s use an integer type, and set all the flags to “Off.”
static int THE_OPTION = 0x00;
Now we’re ready to set, unset, and test some flags! To set the option to “On” for a certain flag, we must turn the bit “On” in our variable. To do this we use the OR operation. I explain why in the example below.
FLAG_C = 4, in 8-bit binary this is 00000100 THE_OPTION = 0, in 8-bit binary 00000000 if we OR them: THE_OPTION |= FLAG_C the binary math looks like: 00000000 OR 00000100 ------------- 00000100
This is a simple example but the point holds. To apply a flag, we apply the OR operator. To remove an option, we use the AND operator.
THE_OPTION = 0B00000100; //binary notation for 4 THE_OPTION &= ~FLAG_C; // THE_OPTION AND-EQUALS NOT FLAG_C the binary math looks like: 00000100 AND 11111011 ------------- 00000000
To check the status of a flag in THE_OPTION, one can simply check:
if(THE_OPTION & FLAG_F) { //do things }
These can also be chained, for instance
#include "stdio.h" enum FLAGS { FLAG_A = 0x01,// 1 FLAG_B = 0X02,// 2 FLAG_C = 0X04,// 4 FLAG_D = 0X08,// 8 FLAG_E = 0X10,// 16 FLAG_F = 0X20 // 32 // so on and so forth }; static int THE_OPTION = 0x00; void test_options() { char line[512], *p; p = &line; p += sprintf(p,"THE_OPTION contains "); if(FLAG_A & THE_OPTION) { p += sprintf(p, "FLAG_A and "); } if(FLAG_B & THE_OPTION) { p += sprintf(p, "FLAG_B and "); } if(FLAG_C & THE_OPTION) { p += sprintf(p, "FLAG_C and "); } if(FLAG_D & THE_OPTION) { p += sprintf(p, "FLAG_D and "); } if(FLAG_E & THE_OPTION) { p += sprintf(p, "FLAG_E and "); } if(FLAG_F & THE_OPTION) { p += sprintf(p, "FLAG_F and "); } printf("%s, that is all.\n", line); } int main() { THE_OPTION = (FLAG_A | FLAG_C | FLAG_F); test_options(); THE_OPTION &= ~FLAG_A; test_options(); THE_OPTION &= ~(FLAG_C | FLAG_F); test_options(); THE_OPTION = 0XFF; test_options(); return 0; }
That will print
THE_OPTION contains FLAG_A and FLAG_C and FLAG_F and , that is all. THE_OPTION contains FLAG_C and FLAG_F and , that is all. THE_OPTION contains , that is all. THE_OPTION contains FLAG_A and FLAG_B and FLAG_C and FLAG_D and FLAG_E and FLAG_F and , that is all.
This post is by no means an exhaustive list of the ways bit fields can be used, however these are the basic ways you can use them. Bit fields are a good choice in applications where memory is limited, or there are lots of boolean data points that need to be stored since one 32 bit variable can hold all the same data as 32 bool types in C. I hope this post was clear and somewhat educational! If you have anything to add send me some mail over on theĀ contact page!