<

[.NET] Bit Flags Explained

Published on
11,288 Points
5,188 Views
1 Endorsement
Last Modified:
Approved
Bit flags and bit flag manipulation is perhaps one of the most underrated strategies in programming, likely because most programmers developing in high-level languages rely too much on the high-level features, and forget about the low-level ones. Their role in programming, however, is still prominent, and likely will be for quite some time.

First of all, what are bit flags? A 'set' of flags is just a binary value, usually 8, 16, 32 or 64 bits long. They are usually expressed via enumerations, though I have seen cases where they are done strictly via hard-coded numeric values (which I don't advise doing). 32 bits is the default for .NET enumerations. Obviously, everything we do is technically binary--numbers, letters, strings, everything, so a set of flags is no different than your average integer. The differences lies in how we visualize the integer, and how we treat it. The difference is in the intent, not in the actual implementation of details of the objects. Anything in the computer world is binary, and anything that is binary can be visualized by us, either into 0's and 1's, or a base-10 number (which is any number you usually encounter, such as 23, 45, 50, or what have you).

As you know, every value in any programming languages can be expressed in binary. The whole "0100101" thing we do is not actually binary--it's just how we, as humans, visualize binary. I'll be using that visualization throughout this article, and it will be geared towards C#. For this article, I'm going to assume you're familiar with how binary works. I suggest you review that link if you cannot accurately convert numbers to and from binary until you can do so.

There are four main operators (common throughout most languages) that allow for useful manipulation of and 'interpretation' of these bits in no significant order:

Logical OR - binary operator, also known as Bitwise OR.
Logical AND - binary operator, also known as Bitwise AND.
Logical XOR - binary operator, also known as Bitwise XOR.
Complement - unary operator, also known as Bitwise NOT, or the NOT operator.

First, I'll take an example directly from the .NET Framework--The FontStyle enumeration. As you know, you can combine different styles to make one style for most fonts. For example, if you wanted a font to be both Bold and Italic, you would combine the Bold and Italic flags like so:

FontStyle boldItalic = FontStyle.Bold | FontStyle.Italic;

Open in new window


This is all well and great, but why does it work? Let's take a look at the FontStyle enumeration, taken from Metadata via Visual Studio 2008 (cleaned up a bit for your benefit):

[Flags]
public enum FontStyle
{
    Regular = 0,
    Bold = 1,
    Italic = 2,
    Underline = 4,
    Strikeout = 8
}

Open in new window


Notice a pattern yet? You should, as the values are dictated by the binary system. Each number is the result of taking 2 to the power of x, where x is incremented by 1, starting at 0. The first value, however, is 0, and (as you know), no exponent can make a number 0. This just means that all other values are turned 'off'. You can't very well have something Regular AND Italic at the same time, now can you? It would just be Italic.

Now let's look at the binary representations of these numbers:

00000000 = Regular
00000001 = Bold
00000010 = Italic
00000100 = Underline
00001000 = Strikeout

Notice a pattern now? I put the Strings on the right so the numbers would line up, by the way. You should notice that no two bits are on at the same time for each value, so each value is 'unique'.

So this is all well and great, but how do we actually use this amazing knowledge? There four distinct operators that are particularily useful for manipulating these bits to your benefit:

Remember that Bitwise OR (|) compares corresponding bits, and if either bit is 1, it produces a 1 for that bit, too. With this knowledge, let's take a look at FontStyle.Bold (value of 1) OR'ed by FontStyle.Italic (value of 2):

   00000001
|  00000010
   00000011

In other words, BoldItalic has a value of 3. This value can't be confused with any other value, because no other value has this combination of bits. This also works for any combination you wish to use. Or, of course, you could express it like this (not advisable):

FontStyle boldItalic = (FontStyle)3;

Open in new window


Now let's assume it's your job to analyze a set of bits and tell which flags are on. For simplicitly's sake, we'll create a general method that checks if a specific flag is set on a FontStyle:

public static Boolean CheckIsOn(FontStyle style, FontStyle flags)
{
     // Check if "flags" are on in the "style" set
}

Open in new window


There are a few ways to check if a flag is on (or off) in a set of flags, but I'll only explain one, as one is all you'll need. Bitwise AND does the same as Bitwise OR, except it returns a 1 only if both corresponding bits are 1. So if we & style by flags, and the result is equal to "flags", we know that all the flags specified by "flags" are on. I'm saying "flags" in plural because we could pass a combined value as the parameter to "flags", so the following would be a valid call (given that someFontStyle is a properly declared FontStyle instance):

CheckIsOn(someFontStyle, FontStyle.Strikeout | FontStyle.Italic);

Open in new window


The implementation of the method could look like this:

return (style & flags) == flags;

Open in new window


You might be saying "well why don't we just & style by flags and check if the result is 0? If it isn't 0, obviously the flags are on!" Actually, no--this would only check if at least one of the flags specified in "flags" were on in the "style" parameter. Perhaps a seperate method would be more appropriate to check if any of the flags specified in the "flags" parameter are on in the "style" parameter:

public static Boolean CheckIsAnyOn(FontStyle style, FontStyle flags)
{
     return (style & flags) != 0;
}

Open in new window


Now what happens if we want to turn a flag off for a certain set of flags? Surely we don't have to check each flag? Nope, this is where another operator comes into play, which is the Complement operator. It's pretty basic--it just inverts all the bits in the value you provide. Unlike the other operators, it accepts only one operand. With this operator in hand, we can implement a TurnFlagsOff method:

public static FontStyle TurnFlagsOff(FontStyle style, FontStyle flags)
{
     return (style & (~flags));
}

Open in new window


The implementation for the TurnFlagsOn method should already be apparent to you, if you'd like to implement one.

Now what about toggling a value on and off? Sure, you can check if it the flag is on, set it on if it isn't, and turn it off if it is, but this sounds like a big pain. That's why there's one more operator for us to use--the Exclusive OR (XOR) operator. It does the same as the bitwise OR and bitwise AND operators, except it will produce a 1 only if one of the two operands is true, an the other is false. If both are false or both are true, it returns a 0. With this knowledge, we can implement a ToggleFlags method:

public static FontStyle ToggleFlags(FontStyle style, FontStyle flags)
{
     return style ^ flags;
}

Open in new window


The last two operators that can prove useful in bit flag manipulation are the Left Shift and Right Shift operators. Explore these of your own accord, as their uses in this context are usually pretty rare, but they can be invaluable when you do find yourself in need of them.

The last piece of knowledge you'll need to start implementing your own flag manipulation techniques is how to create your own enum in C#. Follow the pattern I mentioned above (sticking to powers of two), and remember to apply the FlagsAttribute Attribute to the enumeration. Remember that you can use your enumerated values within your enumeration as public fields (technically, they are, anyway). You could implement a Cheese enumeration, if you really wanted to, like the following:

[Flags]
public enum Cheese
{
      Any = 0,
      American = 1,
      Cheddar = 2,
      Pepperjack = 4,
      ColbyJack = 8,
      Parmesian = 16,
      // etc...
      // If you want, you can do combined values built in, too:
      AmericanAndCheddar = American | Cheddar,
      AmericanAndCheddarAndPepperjack = AmericanAndCheddar | Pepperjack,
      All = American | Cheddar | Pepperjack | ColbyJack | Parmesian // etc...
      // And on and on, until your fingers bleed... Though not required. Or recommended :P
}

Open in new window


Another, rather impressive article coded in C++ regarding bit flags can be found here at EE as well.

I hope this has helped, and I hoped you enjoyed reading,
Nate
1
Comment
0 Comments

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Join & Write a Comment

When you have multiple client accounts to manage, it often feels like there aren’t enough hours in the day. With too many applications to juggle, you can’t focus on your clients, much less your growing to-do list. But that doesn’t have to be the cas…
Learn the basics of Skype For Business in office 365
Other articles by this author

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month