Musings of a Programmer

Rarely-used blog of Dan Harper.
View all blog posts

Bitmasks

April 16, 2021

Bitmasks, and the bitwise operators, are something I've known about/can recognise, but had never actually needed to use them. The first time was when using Windows C++ APIs, and I tripped up over myself a few times trying to use it... So, here's what I wish I read at the start.

tldr

  • Add flags using OR |:
    • flags |= BORDER_LEFT
    • flags |= BORDER_LEFT | BORDER_RIGHT
  • Remove flags using AND & and NOT ~:
    • flags &= ~BORDER_LEFT
    • flags &= ~(BORDER_LEFT | BORDER_RIGHT)
  • Toggle flags using XOR ^:
    • flags ^= BORDER_LEFT
    • flags ^= BORDER_LEFT | BORDER_RIGHT
  • Check any flags using AND &:
    • flags & BORDER_LEFT
    • flags & (BORDER_LEFT | BORDER_RIGHT)
    • e.g.
      • if (flags & BORDER_LEFT) { ... }
      • if (flags & (BORDER_LEFT | BORDER_RIGHT) != 0) { ... }
    • the result of the AND is the same as the flag if it's present, or 0 if it's not
  • Check all flags using AND & and equality ==:
    • flags & BORDER_LEFT == BORDER_LEFT
    • flags & (BORDER_LEFT | BORDER_RIGHT) == (BORDER_LEFT | BORDER_RIGHT)
    • e.g.
      • toCheck = BORDER_LEFT | BORDER_RIGHT
      • if (flags & toCheck == toCheck) { ... }

See in Repl.it

Flags

You'll often see bitmasks used for "flags", for example:

BORDER_LEFT = 0b0001 // 0b is the prefix for a binary number
BORDER_RIGHT = 0b0010
BORDER_TOP = 0b0100
BORDER_BOTTOM = 0b1000

OR |

The | operator sets a bit to 1 if either of the bits in that position are 1. We can use this to combine flags together:

BORDER_VERTICAL   = BORDER_TOP | BORDER_BOTTOM
//   0100
// | 1000
// = 1100

BORDER_HORIZONTAL = BORDER_LEFT | BORDER_RIGHT
//   0001
// | 0010
// = 0011

BORDER_ALL = BORDER_VERTICAL | BORDER_HORIZONTAL
//   1100
// | 0011
// = 1111

myBorders = BORDER_HORIZONTAL | BORDER_BOTTOM
//   0011
// | 1000
// = 1011

AND &

The & operator sets a bit to 1 if both of the bits in that position are 1. We can use this to check a flag:

myBorders = BORDER_TOP | BORDER_HORIZONTAL
// 0111

hasTopBorder = myBorders & BORDER_TOP
//   0111
// & 0100
// = 0100

hasBottomBorder = myBorders & BORDER_BOTTOM
//   0111
// & 1000
// = 0000

NOT ~

The ~ operator inverts the bits in a number. Anything which was 0 is now 1, and anything which was 1 is now 0.

BORDER_BOTTOM
// 1000

~BORDER_BOTTOM
// 0111

~~BORDER_BOTTOM
// 1000

We can use this, alongside the & operator to remove a flag:

flags = BORDER_TOP | BORDER_LEFT | BORDER_RIGHT
// 0111

flagsToRemove = BORDER_TOP
// 0100

flags &= ~flagsToRemove
//   0111
// & 1011 <-- NOT of 0100
// = 0011

XOR ^

The ^ operator sets a bit to 1 if the bits in that position are different. We can use this to toggle a flag:

flags = BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT
//   1000
// | 0001
// | 0010
// = 1011

flags ^= BORDER_LEFT
//   1011
// ^ 0001
// = 1010

flags ^= BORDER_LEFT
//   1010
// ^ 0001
// = 1011

Prefer videos?

Check out this video by The Cherno on YouTube: