Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a bitmask in C#

Tags:

c#

bitmask

Let's say I have the following

int susan = 2; //0010 int bob = 4; //0100 int karen = 8; //1000 

and I pass 10 (8 + 2) as a parameter to a method and I want to decode this to mean susan and karen

I know that 10 is 1010

but how can I do some logic to see if a specific bit is checked as in

if (condition_for_karen) // How to quickly check whether effective karen bit is 1 

Right now all i can think of is to check whether the number i passed is

14 // 1110 12 // 1100 10 // 1010 8 //  1000 

When I have a larger number of actual bits in my real world scenario, this seems impractical, what is a better way using a mask to just check whether or not I meet the condition for just karen?

I can think of shifting left then back then shifting right then back to clear bits other than the one I'm interested in, but this also seems overly complex.

like image 828
Matt Avatar asked Jul 16 '10 02:07

Matt


People also ask

What is a bitmask C?

Bit masking is simply the process of storing data truly as bits, as opposed to storing it as chars/ints/floats. It is incredibly useful for storing certain types of data compactly and efficiently. The idea for bit masking is based on boolean logic.

When should you use a bitmask?

Bitmasks are used when you want to encode multiple layers of information in a single number. So (assuming unix file permissions) if you want to store 3 levels of access restriction (read, write, execute) you could check for each level by checking the corresponding bit.

How do you mask a bit to zero?

In a bit mask, Bitwise AND can be used to make sure particular bits in the result value are set to 0. The trick is to put a 1 in the mask for any bit you do not want changed in the result, and a 0 in the mask for any bit that you want to make sure is a 0 in the result.

Is Bitmask and bit manipulation same?

Bitmasks are a type of bit manipulation, usually performed using the bitwise AND operator to read or clear a specific number of bits. It can also refer to setting, clearing, and toggling individual bits in a bit field.


Video Answer


2 Answers

The traditional way to do this is to use the Flags attribute on an enum:

[Flags] public enum Names {     None = 0,     Susan = 1,     Bob = 2,     Karen = 4 } 

Then you'd check for a particular name as follows:

Names names = Names.Susan | Names.Bob;  // evaluates to true bool susanIsIncluded = (names & Names.Susan) != Names.None;  // evaluates to false bool karenIsIncluded = (names & Names.Karen) != Names.None; 

Logical bitwise combinations can be tough to remember, so I make life easier on myself with a FlagsHelper class*:

// The casts to object in the below code are an unfortunate necessity due to // C#'s restriction against a where T : Enum constraint. (There are ways around // this, but they're outside the scope of this simple illustration.) public static class FlagsHelper {     public static bool IsSet<T>(T flags, T flag) where T : struct     {         int flagsValue = (int)(object)flags;         int flagValue = (int)(object)flag;          return (flagsValue & flagValue) != 0;     }      public static void Set<T>(ref T flags, T flag) where T : struct     {         int flagsValue = (int)(object)flags;         int flagValue = (int)(object)flag;          flags = (T)(object)(flagsValue | flagValue);     }      public static void Unset<T>(ref T flags, T flag) where T : struct     {         int flagsValue = (int)(object)flags;         int flagValue = (int)(object)flag;          flags = (T)(object)(flagsValue & (~flagValue));     } } 

This would allow me to rewrite the above code as:

Names names = Names.Susan | Names.Bob;  bool susanIsIncluded = FlagsHelper.IsSet(names, Names.Susan);  bool karenIsIncluded = FlagsHelper.IsSet(names, Names.Karen); 

Note I could also add Karen to the set by doing this:

FlagsHelper.Set(ref names, Names.Karen); 

And I could remove Susan in a similar way:

FlagsHelper.Unset(ref names, Names.Susan); 

*As Porges pointed out, an equivalent of the IsSet method above already exists in .NET 4.0: Enum.HasFlag. The Set and Unset methods don't appear to have equivalents, though; so I'd still say this class has some merit.


Note: Using enums is just the conventional way of tackling this problem. You can totally translate all of the above code to use ints instead and it'll work just as well.

like image 151
Dan Tao Avatar answered Oct 06 '22 12:10

Dan Tao


if ( ( param & karen ) == karen ) {   // Do stuff } 

The bitwise 'and' will mask out everything except the bit that "represents" Karen. As long as each person is represented by a single bit position, you could check multiple people with a simple:

if ( ( param & karen ) == karen ) {   // Do Karen's stuff } if ( ( param & bob ) == bob )   // Do Bob's stuff } 
like image 26
eldarerathis Avatar answered Oct 06 '22 11:10

eldarerathis