This article deals with the basic concept of bitmasks, something that still causes some confusion at times. I assume you are familiar with C# enums in general and aware of how they represent numerical values and such. If you feel uncertain about this, please read about enums at MSDN first, and then continue here.

- Hey, I’d like a value that is a combination of A and B.
- Sure, here it is: ‘A or B’
- Um... I think you got that wrong… shouldn’t it be ‘A and B’?

I have noticed that using bitmasks is something seems quite confusing for many developers. One source of that confusion might be the name of the operators used when dealing with them. It simply seems backwards for many that the ‘OR’ operator is used for producing a combined bitmask value, while the ‘AND’ operator is used for pulling out a single value from a bitmask. One reason might be that the meaning of and and or in the spoken language seem (but really is not) sort of opposite the meaning when dealing with bitwise operations in programming, where we use the bitwise OR operator (| in C#) for combining values into a bitmask, and the bitwise AND operator (&) to pull out a single value from a bitmask.

The typical use of bitmasks in .NET is with flags enumerations. An example of such an enumeration from the base class library is FileAttributes:

[Flags]
public enum FileAttributes
{
    Archive = 32,
    Compressed = 2048,
    Device = 64,
    Directory = 16,
    Encrypted = 16384,
    Hidden = 2,
    Normal = 128,
    NotContentIndexed = 8192,
    Offline = 4096,
    ReadOnly = 1,
    ReparsePoint = 1024,
    SparseFile = 512,
    System = 4,
    Temporary = 256
}

Note: for the sake of simplicity I have removed a couple of attributes from the declaration that is of no importance for the content of this article.

There are two characteristics that are important in the declaration of this enum:

  • The Flags attribute
  • The values given to each member

The Flags attribute indicates for the compiler that the enum may be used as a bitmask, so it will allow bitwise operations on values of that type.

The sequence of values is also very important. If you sort the numbers, you will see that the used values are 1, 2, 4, 8, 16, 32, 64 and so on. All these are powers of two. By using that particular sequence of numbers, you ensure that any bitwise combination of values will produce a unique result (and the reason for this will become clear in a moment).

Let’s look at a code sample of using the FileAttributes enum:

File.SetAttributes(path, FileAttributes.System | FileAttributes.ReadOnly);

What does FileAttributes.System | FileAttributes.ReadOnly in the above code sample really mean? First, let’s look up the value for the members in the enum declaration.

[Flags]
public enum FileAttributes
{
    [...]
    ReadOnly = 1,
    System = 4,
    [...]
}

So, ReadOnly is 1 and System is 4. As you know, an enum represents values of the type int (unless otherwise stated). This means that we can cast any FileAttributes value to an int and get a numerical representation of the value. In our case (int)(FileAttributes.System | FileAttributes.ReadOnly) gives the value 5. You might think that this happened through a regular addition. After all, 4+1=5, right? Well, it’s not quite that simple. Consider the following sample:

[Flags]
public enum WierdEnum
{
    First = 5,
    Second = 5
}


Console.WriteLine((int)(WierdEnum.First | WierdEnum.Second));

The code above prints 5 and not 10, so obviously we are not talking about addition here. If we move back to our FileAttributes sample, we had two members with the values 4 and 1. Let’s examine what those values look like on the bit level (showing the lowest 8 bits of the int values):

bits for the values 4 and 1

Did you notice something special with those two values? In each value, exactly one bit was set to 1. Each bit represents a value that is a power of two. Here is an 8 bit number, showing the value of each bit.

Values for 8 lowest bits

As you see, if all 8 bits are set this represents the number 255, the largest number that can be stored in a byte.

The | operator will produce a value where each bit in the result becomes 1 if it is 1 in one or the other operand (or in both). In our case:

logical-OR

Now it should be quite clear why we use bitwise OR to combine values. Let’s move on to checking whether the value of a certain enum member is present in the bitmask.

Note that as of .NET 4, you can use the Enum.HasFlag method to determine whether a certain flag is present. For the purpose of examining the underlying mechanics, I will stick to the old fashioned way of doing it here.

Let’s say we have a method that returns a value indicating whether a file is ReadOnly or not:

public static bool FileIsReadOnly(string path)
{
    return (File.GetAttributes(path) & FileAttributes.ReadOnly) != 0;
}

Now we use the & operator instead. We take the FileAttributes value from the file (which may contain a combination of flags), and we perform a bitwise AND operation using that value and the flag we want to check (FileAttributes.ReadOnly). If the result is not zero, the flag is set. This works just like with the | operation described above, but with &, each bit in the result is 1 only if it is 1 in both operands. If the bit is 0 in one or both of the operands, the bit is 0 in the result as well.

Let's assume that the File.GetAttributes call returns FileAttributes.System | FileAttributes.ReadOnly (which we already determined corresponds to the int value 5), and we want to test for the ReadOnly flag (which has the value 1):

logical-AND

As you can see, only the lowest bit is 1 in both operands, so only that bit is 1 in the result. If we were instead to test for the flag FileAttributes.Hidden (having the int value 2), we would get this:

logical-AND-flag-not-set

…which should be expected; the flag value was FileAttributes.System | FileAttributes.ReadOnly, and FileAttributes.Hidden is not part of that value.

So in the end, using a bitwise or operation to combine values, and a bitwise and operation to split them up is not weird at all. Quite the contrary, it’s rather logical.


I am working for a great consultancy company called Diversify, located in Sweden. We are hiring skilled .NET developers. If you are interested, don't hesitate to get in touch with me.

Comments

June 1. 2011 13:04

Johan

din gamla favvo, bitmaskar å enums Smile tror att du skulle trivas med att koda i konstiga inbäddade system där man har ngra få kB att jobba med. Bra skrivet, tackar !

Johan

June 30. 2011 21:42

Warren Chu

Good article. However, you are mixing up the common names for these operators:

bitwise AND: &
logical AND: &&
bitwise OR: |
logical OR: ||

Though you mention the use of these operator seems contrary to one another, both ANDs and ORs do represent "logical conjunction" (A∧B) and "logical disjunction" (A∨B) respectively. Bitwise operators are used for bit or "binary" operations while logical operators are used for comparison, hence the short-circuiting behavior or logical OR (||) and hence the typically root of the confusion.

Warren Chu

June 30. 2011 22:11

Fredrik

Warren, thanks for pointing that out. Correct of course, sloppy of me to miss that. The text is updated Smile

Fredrik