May 31, 2011 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 ORoperator (| in C#) for combining values into a bitmask, and the bitwise ANDoperator (&) 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:
Flags
attributeThe 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):
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.
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 orthe other operand (or in both). In our case:
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):
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:
…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.