[.NET] Bit Flags Explained

AID: 2070
  • Status: Published

3000 points

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;
                                    
1:

Select allOpen 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
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:

Select allOpen 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;
                                    
1:

Select allOpen 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
}
                                    
1:
2:
3:
4:

Select allOpen 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);
                                    
1:

Select allOpen in new window



The implementation of the method could look like this:

return (style & flags) == flags;
                                    
1:

Select allOpen 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;
}
                                    
1:
2:
3:
4:

Select allOpen 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));
}
                                    
1:
2:
3:
4:

Select allOpen 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;
}
                                    
1:
2:
3:
4:

Select allOpen 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
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:

Select allOpen 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
Asked On
2009-12-06 at 16:27:22ID2070
Tags

Bit Flags

,

BitFlags

,

Flags

,

Binary

,

FlagsAttribute

,

enum

,

enums

,

enumerations

,

Bitwise

,

bitwise OR

,

bitwise AND

,

bitwise XOR

,

OR

,

AND

,

XOR

,

logical OR

,

logical AND

,

logical XOR

Topic

C# Programming Language

Views
2414

Comments

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top C# Experts

  1. kaufmed

    566,376

    Sage

    500 points yesterday

    Profile
    Rank: Genius
  2. BuggyCoder

    240,764

    Guru

    10 points yesterday

    Profile
    Rank: Sage
  3. navneethegde

    158,560

    Guru

    0 points yesterday

    Profile
    Rank: Wizard
  4. CodeCruiser

    140,708

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  5. TheLearnedOne

    137,350

    Master

    2,800 points yesterday

    Profile
    Rank: Savant
  6. wdosanjos

    124,511

    Master

    3,500 points yesterday

    Profile
    Rank: Genius
  7. AndyAinscow

    107,357

    Master

    0 points yesterday

    Profile
    Rank: Genius
  8. Dhaest

    98,335

    Master

    0 points yesterday

    Profile
    Rank: Genius
  9. Idle_Mind

    91,914

    Master

    0 points yesterday

    Profile
    Rank: Savant
  10. tommyBoy

    90,068

    Master

    0 points yesterday

    Profile
    Rank: Genius
  11. nishantcomp2512

    89,000

    Master

    0 points yesterday

    Profile
    Rank: Wizard
  12. MlandaT

    86,553

    Master

    0 points yesterday

    Profile
    Rank: Genius
  13. Chinmay_Patel

    80,818

    Master

    0 points yesterday

    Profile
    Rank: Genius
  14. ddayx10

    66,538

    Master

    0 points yesterday

    Profile
    Rank: Sage
  15. anarki_jimbel

    66,132

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  16. ambience

    63,764

    Master

    0 points yesterday

    Profile
    Rank: Sage
  17. ukerandi

    62,593

    Master

    1,000 points yesterday

    Profile
    Rank: Guru
  18. apeter

    60,772

    Master

    0 points yesterday

    Profile
    Rank: Sage
  19. JamesBurger

    60,305

    Master

    0 points yesterday

    Profile
    Rank: Sage
  20. sedgwick

    52,750

    Master

    1,600 points yesterday

    Profile
    Rank: Genius
  21. emoreau

    50,917

    Master

    0 points yesterday

    Profile
    Rank: Genius
  22. ged325

    50,311

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  23. anuradhay

    49,977

    2,500 points yesterday

    Profile
    Rank: Guru
  24. techChallenger1

    47,638

    0 points yesterday

    Profile
    Rank: Guru
  25. mas_oz2003

    43,540

    0 points yesterday

    Profile
    Rank: Genius

Hall Of Fame