120

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.

Matt
  • 25,943
  • 66
  • 198
  • 303
  • 9
    Just had to comment on usage. If you are performing bit operations, you should only use bit manipulating operators. i.e., think of it as (8 | 2), not (8 + 2). – Jeff Mercado Jul 16 '10 at 02:37

6 Answers6

237

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.

Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • 15
    +1 for being the first code to actually work. You can also do `(names & Names.Susan) == Names.Susan`, which doesn't require a `None`. – Matthew Flaschen Jul 16 '10 at 02:28
  • 2
    @Matthew: Oh yeah, good point. I guess I just get in the habit of always defining a `None` value for all my enums, as I find it ends up being convenient in many scenarios. – Dan Tao Jul 16 '10 at 02:37
  • 37
    This is built in, you don't need your helper methods... `var susanIsIncluded = names.HasFlag(Names.Susan);` – porges Jul 16 '10 at 03:00
  • 3
    @Porges: Wow, no idea how I missed that... thanks for pointing that out! (Looks like it's only available as of .NET 4.0, though... also, there's no equivalent for the `Set` method. So, I'd say the helper methods are at least not *totally* worthless.) – Dan Tao Jul 16 '10 at 03:29
  • `"also, there's no equivalent for the Set method"` I think this is probably because set is much easier to write out than `HasFlag`: `names | Names.Susan`. Unset gets more complicated, so I don't know why they didn't just include all of them... – porges Jul 16 '10 at 05:42
  • @Porges: Well, I never argued that the code in these methods was difficult to *write out*. It's more that whenever these kinds of operations are needed, I have to stop for a second and actually think about bits before I remember how they work. By abstracting these into methods, like I said, "I make life easier" for myself. Plus, as you hinted, the `Set` method's really more there for completeness than anything else. – Dan Tao Jul 16 '10 at 11:43
  • 6
    Note, that using `names.HasFlag(Names.Susan)` is like `(names & Names.Susan) == Names.Susan` which is not always like `(names & Names.Susan) != Names.None`. For example if you'll check if `names.HasFlag(Names.none)` or `names.HasFlag(Names.Susan|Names.Karen)` – A.B.Cade Jul 12 '12 at 04:33
  • +1 for great utility function. I ran into issues with illegal casting operations, but it was because I had a `MyEnum : byte` typing. – Kyle Baran May 25 '14 at 03:18
27

Easy Way:

[Flags]
public enum MyFlags {
    None = 0,
    Susan = 1,
    Alice = 2,
    Bob = 4,
    Eve = 8
}

To set the flags use logical "or" operator |:

MyFlags f = new MyFlags();
f = MyFlags.Alice | MyFlags.Bob;

And to check if a flag is included use HasFlag:

if(f.HasFlag(MyFlags.Alice)) { /* true */}
if(f.HasFlag(MyFlags.Eve)) { /* false */}
A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
22
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
}
eldarerathis
  • 35,455
  • 10
  • 90
  • 93
13

I have included an example here which demonstrates how you might store the mask in a database column as an int, and how you would reinstate the mask later on:

public enum DaysBitMask { Mon=0, Tues=1, Wed=2, Thu = 4, Fri = 8, Sat = 16, Sun = 32 }


DaysBitMask mask = DaysBitMask.Sat | DaysBitMask.Thu;
bool test;
if ((mask & DaysBitMask.Sat) == DaysBitMask.Sat)
    test = true;
if ((mask & DaysBitMask.Thu) == DaysBitMask.Thu)
    test = true;
if ((mask & DaysBitMask.Wed) != DaysBitMask.Wed)
    test = true;

// Store the value
int storedVal = (int)mask;

// Reinstate the mask and re-test
DaysBitMask reHydratedMask = (DaysBitMask)storedVal;

if ((reHydratedMask & DaysBitMask.Sat) == DaysBitMask.Sat)
    test = true;
if ((reHydratedMask & DaysBitMask.Thu) == DaysBitMask.Thu)
    test = true;
if ((reHydratedMask & DaysBitMask.Wed) != DaysBitMask.Wed)
    test = true;
RThomas
  • 10,702
  • 2
  • 48
  • 61
Nick Wright
  • 1,403
  • 13
  • 19
  • I did something similar but when defining the mask I did Mon=Math.Power(2, 0), Tues=Math.Pow(2, 1), Wed=Math.Pow(2, 2), etc. so the bit position is a little more obvious for those of use who aren't used to binary to decimal conversion. Blindy's is good too since it turns into a boolean result by shifting the masked bit. – Analog Arsonist Jan 26 '17 at 16:06
7

To combine bitmasks you want to use bitwise-or. In the trivial case where every value you combine has exactly 1 bit on (like your example), it's equivalent to adding them. If you have overlapping bits however, or'ing them handles the case gracefully.

To decode the bitmasks you and your value with a mask, like so:

if(val & (1<<1)) SusanIsOn();
if(val & (1<<2)) BobIsOn();
if(val & (1<<3)) KarenIsOn();
Blindy
  • 65,249
  • 10
  • 91
  • 131
  • 2
    You can't use an integer as a boolean in C#. – Shadow May 23 '19 at 22:58
  • Correct you cannot use an integer as a boolean, however you can check what the integer is instead... `if((val & (1<<1) > 0)) SusanIsOn(); ` `if((val & (1<<2) > 0)) BobIsOn();` `if((val & (1<<3) > 0)) KarenIsOn();` – Neil Higgins Aug 25 '22 at 13:34
0

One other really good reason to use a bitmask vs individual bools is as a web developer, when integrating one website to another, we frequently need to send parameters or flags in the querystring. As long as all of your flags are binary, it makes it much simpler to use a single value as a bitmask than send multiple values as bools. I know there are otherways to send data (GET, POST, etc.), but a simple parameter on the querystring is most of the time sufficient for nonsensitive items. Try to send 128 bool values on a querystring to communicate with an external site. This also gives the added ability of not pushing the limit on url querystrings in browsers