How can I remove a flag in C?
Asked Answered
K

3

177

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;
Koehn answered 13/10, 2010 at 2:1 Comment(1)
You may find the answers to the SO question "How do you set, clear and toggle a single bit in C" helpful.Celik
R
402

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)
Reimer answered 13/10, 2010 at 2:41 Comment(5)
@Aaron: I'm glad it helped. I initially had trouble understand bitwise operations until someone took 10 minutes to explain it on paper.Reimer
@Reimer I thought XOR would work to remove an already set flag. notification.sound ^= Notification.DEFAULT_SOUND;Colligate
How do you enable Walk? Since X | 0 == XFarewell
As @Farewell 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.Istanbul
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.Karlin
C
102
my.emask &= ~(ENABLE_SHOOT);

to clear a few flags:

my.emask &= ~(ENABLE_SHOOT|SOME_OTHER|ONE_MORE);
Clemence answered 13/10, 2010 at 2:3 Comment(0)
B
16

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.

Bertold answered 16/10, 2010 at 7:25 Comment(2)
+1 for catching the nonobvious corner case. One way to avoid it is to instead use flags -= flags & MY_FLAG; (or ^= if you prefer).Flannelette
@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'Unhair

© 2022 - 2024 — McMap. All rights reserved.