174

There is a variable that holds some flags and I want to remove one of them. But I don't know how to remove it.

Here is how I set the flag.

my.emask |= ENABLE_SHOOT;
Dennis
  • 20,275
  • 4
  • 64
  • 80
Aaron de Windt
  • 16,794
  • 13
  • 47
  • 62
  • 6
    You may find the answers to the SO question ["How do you set, clear and toggle a single bit in C"](http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c) helpful. – schot Oct 13 '10 at 06:28

3 Answers3

393

Short Answer

You want to do an Bitwise AND operation on the current value with a Bitwise NOT operation of the flag you want to unset. A Bitwise NOT inverts every bit (i.e. 0 => 1, 1 => 0).

flags = flags & ~MASK; or flags &= ~MASK;.

Long Answer

ENABLE_WALK  = 0    // 00000000
ENABLE_RUN   = 1    // 00000001
ENABLE_SHOOT = 2    // 00000010
ENABLE_SHOOTRUN = 3 // 00000011

value  = ENABLE_RUN     // 00000001
value |= ENABLE_SHOOT   // 00000011 or same as ENABLE_SHOOTRUN

When you perform a Bitwise AND with Bitwise NOT of the value you want unset.

value = value & ~ENABLE_SHOOT // 00000001

you are actually doing:

      0 0 0 0 0 0 1 1     (current value)
   &  1 1 1 1 1 1 0 1     (~ENABLE_SHOOT)
      ---------------
      0 0 0 0 0 0 0 1     (result)
Dennis
  • 20,275
  • 4
  • 64
  • 80
  • @Aaron: I'm glad it helped. I initially had trouble understand bitwise operations *until* someone took 10 minutes to explain it on paper. – Dennis Oct 14 '10 at 01:08
  • 1
    @Dennis I thought XOR would work to remove an already set flag. `notification.sound ^= Notification.DEFAULT_SOUND;` – likejudo Apr 14 '14 at 09:56
  • 3
    How do you enable Walk? Since X | 0 == X – Unikorn Apr 29 '14 at 16:36
  • As @Unikorn points out, a flag value of zero does not work properly, either if you try to OR it on or if you try to AND it off. – RenniePet Dec 14 '14 at 00:41
  • To enable walk, you just have to disable run (which will leave bit 1 set to 0). Don't think of the ENABLE_* flags as decimal numbers, but as binary numbers, either on or off. You still can't _explicitly_ enable or disable walk however. – Jacob Degeling Aug 05 '17 at 09:03
102
my.emask &= ~(ENABLE_SHOOT);

to clear a few flags:

my.emask &= ~(ENABLE_SHOOT|SOME_OTHER|ONE_MORE);
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
15

It's important to note that if the variable being manipulated is larger than an int, the value used in the 'and not' expression must be as well. Actually, one can sometimes get away with using smaller types, but there are enough odd cases that it's probably best to use type suffixes to make sure the constants are large enough.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 5
    +1 for catching the nonobvious corner case. One way to avoid it is to instead use `flags -= flags & MY_FLAG;` (or `^=` if you prefer). – R.. GitHub STOP HELPING ICE Oct 16 '10 at 07:52
  • 1
    @R.. I would have used '^=' except it will toggle the bits and sometimes you might not know which of the many flags are set. If I want to make sure the two right most bits are zero, e.g. my.emask: '0 1 0 1' input: '0 0 1 1' with: '^=' '0 1 1 0' with: '& ~' '0 1 0 0' – Hector Mar 26 '15 at 17:18