Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Bit Fields / Flags Tutorial with Example

extract

  • Please log in to reply
4 replies to this topic

#1 Alexander

Alexander

    YOL9

  • Moderator
  • 3963 posts
  • Location:Vancouver, Eh! Cleverness: 200
  • Programming Language:C, C++, PHP, Assembly

Posted 09 June 2010 - 07:14 PM

C/C++: Bit Flags

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 char in this case). Note that one byte = eight bits:

char 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 Bin Hex| Examples
│││││││└ 2^0 1  | 1+2 is Hex 3 is 00000011
││││││└─ 2^1 2  | 1+8 is Hex 81 is 10000001
│││││└── 2^2 4  | 3,4+6 is Hex 2C is 00101100
││││└─── 2^3 8  | 
│││└──── 2^4 10 |
││└───── 2^5 20 | etc ...
│└────── 2^6 40 |
└─────── 2^7 80 | All is hex FF is 11111111

So we can apply bitwise operators like this:

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

Bitwise OR, A | B = C:
   00000101 (0x5)
OR 00000011 (0x3)
 = 00000111 (0x7)

As you may notice, C holds both options now..

Here we will use our other operator, AND:

Bitwise AND, A & B = C
    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.
 

// 0x31 = 0x1 | 0x10 | 0x20
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!

arguments.c:

#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

And that concludes the lesson!


Edited by Alexander, 10 September 2013 - 05:52 PM.
Reformatted for new forum

  • 0

#2 demonbreath23

demonbreath23

    CC Lurker

  • Just Joined
  • Pip
  • 3 posts

Posted 10 June 2010 - 10:25 PM

thanks for this tutorial.
  • 0

#3 Guest

Guest

    CC Devotee

  • Expert Member
  • PipPipPipPipPipPip
  • 914 posts
  • Programming Language:C

Posted 18 June 2010 - 02:15 AM

Great job on this.
Posted Image
  • 1
Root Beer == System Administrator's Beer
Download the new operating system programming kit! (some assembly required)

#4 FireGator

FireGator

    CC Regular

  • Just Joined
  • PipPipPip
  • 35 posts

Posted 21 September 2010 - 12:15 AM

This was the only tutorial that made sense to me, awesome work. +rep

My only question is: Why do we need to use an unsigned char or integer to store the values as you did, is there any special effect/requirement given with one?
  • 0

#5 Alexander

Alexander

    YOL9

  • Moderator
  • 3963 posts
  • Location:Vancouver, Eh! Cleverness: 200
  • Programming Language:C, C++, PHP, Assembly

Posted 16 November 2010 - 10:11 PM

Why do we need to use an unsigned char or integer to store the values as you did, is there any special effect/requirement given with one?


Signed data types reserve the leftmost (most significant bit) for signedness, i.e. negative representation with a two's complement, removing that feature allows us to use all bits (although the signed bit is still available to us, we should explicitly show we are using all bits)

EDIT: Finally updated this tutorial a lot, with better examples.

Edited by Alexander, 29 May 2011 - 06:25 PM.

  • 0

All new problems require investigation, and so if errors are problems, try to learn as much as you can and report back.






Also tagged with one or more of these keywords: extract

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download