Bit Flags: Example Tutorial


What are bit flags?

Bit flags , or bit fields are a great way of storing several boolean values in a single byte (or set of bytes), and are internally represented as binary. In this tutorial we will work with bitwise operators, so if you need to brush up this is what we’re using; the following key binary operators.

Here they are:

AND (a & b): Bits that are set in both a and b are set.
OR: (a | b): Bits that are set in either a or b are set.
XOR (a ^ b): Bits that are set in a or b but not both are set.
NOT (~a)   : Bits in a are complemented (inversed)

In this lesson we will need to work with an unsigned integer, which can store successfully four bytes of data but for simplicity’s sake we will only work with one (a charin this case). Note that one byte = eight bits:

[COLOR=blue]unsigned char[/COLOR] options;

We will need to define the required options and their bits in an enum field, in here the options will be placed at separate bits in the byte. You may note my simple naming convention, we should avoid using anything too fancy here:

enum Options {
        OPT_A   = 0x01,
        OPT_B   = 0x02,
        OPT_C   = 0x04,
        OPT_D   = 0x08,
        OPT_E   = 0x10,
        OPT_F   = 0x20,
};

Each option will now have its own bit flag, what we will need to understand is its binary representation so we can successfully use bitwise operators. The simple conversion from hexadecimal on what we defined is as follows:

00000000 Meaning          Bin Hex      | Examples
 │││││││└ Preference 1  2^0   1 | Pref 1+2   is Hex 3 is 00000011
 ││││││└─ Preference 2  2^1   2 | Pref 1+8   is Hex 81 is 10000001
 │││││└── Preference 3  2^2   4 | Pref 3,4+6 is Hex 2C is 00101100
 ││││└─── Preference 4  2^3   8 | all Prefs  is Hex FF is 11111111
 │││└──── Preference 5  2^4  10 |
 ││└───── Preference 6  2^5  20 | etc ...
 │└────── Preference 7  2^6  40 |
 └─────── Preference 8  2^7  80 |

So we can apply bitwise operators like this:

Now assume option A is 0x5 and option B is 0x7:

Bitwise OR, A | B = C:
[FONT=Courier New]   00000101 (0x5)
OR 00000011 (0x3)
 = 00000111 (0x7)[/FONT]

As you may notice, both options are now set into C.

Here we will use our other operator:

Bitwise AND, A & B = C
[FONT=Courier New]      00000101 (0x5)
AND 00000011 (0x3)
  = 00000001 (0x1)[/FONT]

A & B = decimal ONE, therefor we can assume B is set as it is non-zero.

This next part I will explain how we may use it in our code, this example shows setting three options (options A, E and F) and then verifying if option F was is set.

//         8*1b                 0x1     0x10    0x20  =  0x31
unsigned char options = OPT_A | OPT_E | OPT_F;

//       0x31 & 0x20 = 0x20 > 0 = true
if (options & OPT_F) {
        printf("Option F is set!");
}

That is essentially it. There are many different aspects of the program you can use bit fields for, from dealing with database formats or setting flags for user permissions. It is a simple and clean method of storing key values without wasting variable space.

As people tend to like darned examples instead of just a lecture, I will write something full to include arguments in my example application!

#include <stdio.h>

//anonymous enum of options, can be done any way you wish
enum {
        OPT_A = 0x01,
        OPT_B = 0x02,
        OPT_C = 0x04,
        OPT_H = 0x08,
};

int main(int argc, char **argv)
{
        //unsigned int, or rather uint32_t = 8*4=32 bits for options if needed, unsigned means last bit is ours to use
        unsigned int opt = 0x0;
        //can do char array for options like '-nodebug'
        char c;

        //extract arguments from argument array.
        while((++argv)[0] && argv[0][0] == '-')
        {
                while((c = *++argv[0]) != 0)
                {
                        switch(c) { 
                        case 'a':
                        //assign option bits to "opt" bit array
                                opt |= OPT_A;  break;
                        case 'b':
                                opt |= OPT_B;  break;
                        case 'c':
                                opt |= OPT_C;  break;
                        case 'h':
                                opt |= OPT_H;  break;
                        //this will happen if they enter an invalid option:
                        default: 
                                printf("%s: Unknown option %c", argv[0], c);
                                return 1; //break out of application
                        }
                }
        }
        
        //apply bitwise AND to check for assignedness a few times
        if(opt & OPT_A)
                printf("Hello World!\n");
   
        if(opt & OPT_B) {
                unsigned int foo;
                foo = 2000;
                printf("Foo has been initialized.\n");
        }
        
        //compare if two flags were specifically set
        if ((opt & (OPT_B | OPT_C)) == (OPT_B | OPT_C)) 
                printf("Flags B and C were set.\n");
        
        if(opt & OPT_H) {
                //print help, may wish to create exit point to stop program from executing
                printf("\tHelp is not implemented yet\n\tAllowable options: [-abch]\n");
                return 0;
        }
  
        //----------------- Some fun extras: ---------------------//
        
        //Reset bitflag completely
        opt = 0;
        
        //Apply bitwise OR to append multiple flags
        opt = (OPT_A | OPT_B | OPT_C);
        
        //Apply bitwise AND+EQUALS to add or remove flags to existing option field
        //Then we apply bitwise NOT (a complement) to remove both flags
        opt &= ~(OPT_A | OPT_B);
        
        //Options A and B are now removed
        
        //Check if BOTH flags are not set
        if ((opt & (OPT_A | OPT_B)) == 0)
                //printf( A and B are not set )

        //check if only one is not set
        if ((opt & OPT_A) == 0)
                //printf( flag A is not set )
                
        //end program
        return 0;
        
}

And that is simply it. You may call the program using any which option you wish, some examples include:

./arguments -a -b
./arguments -abc
./arguments -h
./arguments -z

Related posts:

About author

This article was written by admin

Admin has over twenty years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles. Working presently as Development Manager in India. A firm Believer in Knowledge grows when it shared.

Comments

Comments (1)
  1. Marissa Lansing says - Posted: October 24, 2012

    I’m not sure exactly why but this web site is loading very slow for me. Is anyone else having this problem or is it a issue on my end? I’ll check back later on and see if the problem still exists.

Leave your comment

Your email address will not be published. Required fields are marked *