Published: 27 Dec 2006
By: Derek Smyth

Bitwise operations are a way to use the individual bits of an integer to represent 32 individual boolean flags. Combining this idea with enumerations and bitwise ORs can provide a more readable way to set each of the individual flags.

Introduction

Although the technique could be considered outdated due to the price and amount of memory available on computers these days it is still in use within the .NET framework, as using bitwise operations with enumerations can be a rather useful way to pass multiple boolean settings to a single method.

What is an Integer?

An integer is mostly thought of as a number however there is another way to look at an integer. In memory an integer is represented by a 32 bit binary series of zeros and ones. For example the number 42 is represented in binary as 00101010.

128 64 32 16 8 4 2 1
0 0 1 0 1 0 1 0

32 + 8 + 2 = 42

However if you start to think of the zeros as false and the ones as true then the integer changes and becomes an array of 32 boolean values. This idea is the concept behind bitwise operations.

Bit[7] Bit[6] Bit[5] Bit[4] Bit[3] Bit[2] Bit[1] Bit[0]
128 64 32 16 8 4 2 1
0 0 1 0 1 0 1 0

For example you could have logic in your application that stated, if bit[5] == 1 then x is true, if bit[3] == 1 then y is true, and if bit[1] == 1 then z is true, and so on.

How do Enumerations fit in?

Enumerations make code more readable. I won't insult your intelligence as to why but I'd like to highlight the fact that the elements that make up enumeration are numeric values. This fact allows us to use an enumeration as a means to set an integer's value.

If we continue to think of an integer as an array of 32 boolean values then this means an enumeration allows us to switch one or more of the boolean values. If we're clever about the individual values of the elements that make up the enumeration then we can switch on a specific individual bit of the integer.

For example by giving the enumeration a value that maps to the two base binary then an enumerations can be used as a switch.

public enum Bitwise : int
{
    Setting1 = 1,   //0000 0001
    Setting2 = 2,   //0000 0010
    Setting3 = 4,   //0000 0100
    Setting4 = 8,   //0000 1000
    Setting5 = 16,  //0001 0000
    Setting6 = 32,  //0010 0000
    Setting7 = 64,  //0010 0000
    Setting8 = 128, //0100 0000
    Setting9 = 255, //1000 0000
};

If we use the enumeration Bitwise.Setting6 then bit[5], which represents 32, == 1 and hence, remembering the example above z is true.

With bitwise operations though we can go one further, by performing a bitwise OR we can combine the enumerations to set more than one boolean flag. For example using Bitwise.Setting6 and Bitwise.Setting2 we set two flags to true.

Before continuing the FlagsAttributeattribute can be used to specify that an enumeration should have its values set so that it can be used for bitwise operations. For example the above enumeration can be replaced with the following.

[System.Flags()]
public enum Bitwise2 : int
{
    Setting1, //0000 0001
    Setting2, //0000 0010
    Setting3, //0000 0100
    Setting4, //0000 1000
    Setting5, //0001 0000
    Setting6, //0010 0000
    Setting7, //0010 0000
    Setting8, //0100 0000
    Setting9, //1000 0000
};

Bitwise ORs

To combine enumeration values so that they set multiple boolean flags you use bitwise ORs. Here is an example,

Bitwise settings = Bitwise.Setting2 | Bitwise.Setting4 | Bitwise.Setting8;

The term bitwise OR is a little bit confusing in my mind as the above line of code is easier to read if you think in terms of AND. For example, the Bitwise enumeration setting equals Setting2 and Setting4 and Setting8.

 Which gives the enumeration setting an integer value of 42.

Bit[7] Bit[6] Bit[5] Bit[4] Bit[3] Bit[2] Bit[1] Bit[0]
128 64 32 16 8 4 2 1
0 0 1 0 1 0 1 0
Setting8 Setting7 Setting6 Setting5 Setting4 Setting3 Setting2 Setting1

Accessing the bits of an Integer

There are three things you will need to do with the bits of an integer.

  1. Get the value of a bit
  2. Set the value of a bit to 1
  3. Set the value of a bit to 0

Unfortunately the code to do these three tasks is pretty nasty. For example, to get the value of the first bit of an integer named myIntValue you would use the following code.

myIntValue & (1 << 0)

Not exactly the most understandable piece of code you'll ever comes across and setting the values of individual bits is just as bad, however there is a rather nicer approach you can take that helps keep things cleaner.

The approach involves creating a wrapper for the integer in which an indexer has been created that lets you access the integer as an array of bits and does so in such a way that you can set myIntValue[0] = false, or form logical statements using code like 'if (myIntValue[3] == true)'.

Here is an example of this wrapper, it demonstrates the code that's used to set individual bits of an integer on or off.

public struct IntAsBits
{     
 int settings;

   public IntAsBits(Bitwise settings)
   {
     this.settings = (int)settings;
   }

   public bool this[int index]
   {
     get
     { //check the bit at index and return true or false
       return (settings & (1 << index)) != 0; 
     }
     set
     {
       if (value) 
	settings |= (1 << index); //turns the bit at index on
       else
         settings &= ~(1 << index); //turns the bit at index off
     }
   }
}

This would be used similar to this:

static void Main(string[] args)
{
  Bitwise settings = Bitwise.Setting2 | Bitwise.Setting4 | Bitwise.Setting8;

  IntAsBits bits = new IntAsBits(settings);
  bits.DisplaySettings();

  Console.ReadLine();
}

Which would produce an output similar to below. This demonstrates that by passing a bitwise OR'd enumeration into a method or class gives you the ability to use 32 different boolean settings within that method or class.

ScreenDump.jpg

Word of Warning

This old school approach to memory conservation is rather handy but I need to point out that many new age developers might not know this approach. If you use it in your projects then make sure you fully document what you doing so someone else can pick up the project later.

Summary

Bitwise operations involve treating the individual bits of an integer as an array of 32 boolean flags. By combining this concept with enumerations and bitwise OR's you can enable and disable particular bits in a much more readable fashion and by wrapping an integer in a custom class that provides an indexer you can simplify access to the individual bits and access them as a boolean value. You need to consider though if you really need to take this approach and if you do make sure you document it as it's a somewhat forgotten art.

About Derek Smyth

Sorry, no bio is available

This author has published 6 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Introduction to 3-Tier Architecture
Brian Mains explains the benefits of a 3-tier architecture.
Settings Manager for Windows Vista Sidebar Gadgets
SettingsManager is a JavaScript library that allows Windows Vista Sidebar gadgets to persist common ...
ORM in .NET 3.5
This article covers a general introduction to ORM concepts, the approach that .NET 3.5 takes, and ho...
Delegates in .NET
Rupesh Kumar Nayak explains delegates in .NET.
SuperToolTip
Office 2007 offers great new features, one of them is the SuperTooltip which provides much more info...

You might also be interested in the following related blog posts


Bounded blocking queues read more
TSql vs. SQL CLR Performance Analysis read more
Top
 
 
 

Please login to rate or to leave a comment.

Product Spotlight