3

I was wondering how the following enum masking works

If I have an Enum structure

public enum DelMask
{
        pass = 1,       
        fail = 2,       
        abandoned = 4,        
        distinction = 8,             
        merit = 16,        
        defer = 32,        
}

I have seen the following code

int pass = 48;
if ((pass & (int)DelMask.defer) > 0)
   //Do something
else if ((pass & (int)DelMask.merit ) > 0)
   //Do something else

I am wondering can anyone help me figure out how which block will get executed?

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
Wesley Skeen
  • 7,977
  • 13
  • 42
  • 56
  • 3
    `int pass == 48;` shouldn't compile is it `int pass = 48` ? – Habib Nov 01 '12 at 11:09
  • possible duplicate of [How to Compare Flags in C#?](http://stackoverflow.com/questions/40211/how-to-compare-flags-in-c) – RB. Nov 01 '12 at 11:11
  • 1
    Just to be sure... your enum has the [Flags] attribute, right? – LightStriker Nov 01 '12 at 11:12
  • @Marc-AndréJutras no it is not included. This is code that I am trying to figure out – Wesley Skeen Nov 01 '12 at 11:16
  • Only difference with [Flags] is that you would not have to write the int values in the definition of the enum members. I think there might be some optimizations in the VS code analysis tools too when you use Flags. – Evren Kuzucuoglu Nov 01 '12 at 11:30

5 Answers5

3

Basic bit logic at work here. The integer 48 ends like this in binary:

0011 0000

Defer, 32, is:

0010 0000

Merit, 16, is:

0001 0000

Now when you perform a logical AND (&), the resulting bits are set where they are both in the input:

pass & (int)DelMask.defer

0011 0000 
0010 0000
========= & 
0010 0000    

The result will be 16, so ((pass & (int)DelMask.defer) > 0) will evaluate to true. Both if's will evaluate to true in your example because both flags are present in the input. The second one won't be evaluated though, because it's an else if.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
1

Both are correct so the first will get executed.

16 is 10000

32 is 100000

48 is 16+32 so it is 110000

10000 & 110000 is 10000

100000 & 110000 is 100000

Both are bigger than zero.

Amiram Korach
  • 13,056
  • 3
  • 28
  • 30
1

48 = 16 (merit) + 32 (defer).

Thus pass & (int)DelMask.defer evaluates to 32, so the first block runs.

If that wasn't the case, pass & (int)DelMask.merit evaluates to 16, so the second block would run if it got that far.

This only works because the values in the enum are all different powers of 2 and thus correspond to independent bits in the underlying int. This is what is known as a bit flags enum.

Rawling
  • 49,248
  • 7
  • 89
  • 127
1

First, it should be int pass = 48; Basically this code checks whether a bit is set in a binary representation of the number. Each & operation should produce a result with all zeroes and one on the place where it is in the mask. for instance:

48:         110000
defer = 32: 100000
            ______
          & 100000

So you can use this code:

int pass = 48;
if ((pass & (int)DelMask.defer) == (int)DelMask.defer)
   //Do something
else if ((pass & (int)DelMask.merit ) == (int)DelMask.merit)
   //Do something else
Nikola Davidovic
  • 8,556
  • 1
  • 27
  • 33
1

Well you need to think of those numbers as binary. I'll use the d suffix to show decimal notation and b suffix for binary notation.

enum values:

  • 01d = 000001b
  • 02d = 000010b
  • 04d = 000100b
  • 08d = 001000b
  • 16d = 010000b
  • 32d = 100000b

pass value:

48d = 110000b

Now the & is the bit-wise AND operator. Which means that if c = a&b, the nth bit in c will be 1 if and only if the nth bit is 1 in both a and b.

So:

  • 16d & 48d = 010000b = 16d > 0
  • 32d & 48d = 100000b = 32d > 0

As you see, your number 48d "matches" with both 16d and 32d. That is why this kind of enums is generally described as a "flag" enum: you can have with one integer the value of several "flags".

As for your code, the first if operator will be verified, which means that you will enter it and "Do something". You will not "Do something else".

Generally in C#, we use the [Flags] attribute for flag enums, which allows not actually writing the decimal values for the enum members. As usual, the example in the MSDN is useless so I'll refer to this SO question for more details about how to use it (note that to know if a value x has a flag f set, you can either do x & f == f or x | f == x, but the usage seems to be to generally use the latter one).

Community
  • 1
  • 1
Evren Kuzucuoglu
  • 3,781
  • 28
  • 51