CalculateeLearning paths
C/C++8–10 min read

Bitwise Operations and Register Masks

Set, clear and test individual bits without confusing logical and bitwise operators.

Mental model

A mask is a stencil laid over a row of switches. It selects which positions an operation is allowed to affect.

registermaskOR result100000010000100010001001register |= (1 << 3)
A bit mask sets selected control bits while preserving unrelated bits in the register.
UNDERSTAND THE BEHAVIOR
01

Bitwise AND, OR and XOR operate on corresponding bit positions. Logical AND and OR instead combine truth values and can short-circuit. For example, 2 & 1 is zero because the set bits do not overlap, while 2 && 1 is true because both values are nonzero. Confusing the two changes the meaning of a condition.

02

To select bit three, counting from zero, form the mask 1 shifted left by three. OR with the mask sets that bit; AND with the inverted mask clears it; XOR toggles it. AND with the mask tests whether it is set. Use unsigned types and a shift count smaller than the operand width to avoid invalid or surprising behavior.

03

The example uses an ordinary RAM variable, not a hardware address. A peripheral register may have read-only bits, write-one-to-clear flags or read side effects. For such a register, a read-modify-write expression can accidentally clear or change something else. Consult the register specification and use dedicated set/clear registers when provided.

04

Concurrency also matters: an interrupt or another execution context can update the same value between the read and write. A correct bit mask does not make the entire operation atomic. Use the chip or platform's appropriate atomic register operation or synchronization mechanism when the value is shared.

Why it matters

Set, clear and test individual bits without confusing logical and bitwise operators.

Core ideas

  • Bitwise & differs from logical &&.
  • Check bit numbering and operand width.
  • Hardware register access must follow its documented semantics.
Key equationsSet: value | maskClear: value & ~maskTest: (value & mask) != 0
EXAMPLE

Work through a practical example

1Start with value 0x02, binary 00000010.

2Set bit three using mask 0x08: result 0x0A.

3Clear bit one using mask 0x02: result 0x08.

4Test bit three: the masked result is nonzero, so it is set.

Common mistake

Using a generic read-modify-write sequence on a write-one-to-clear status register.

Code example

C++17 — standalone RAM example; expected output: 8 1

#include <cstdint>
#include <cstdio>
int main() {
  std::uint32_t flags = 0x02u;
  flags |= (std::uint32_t{1} << 3);
  flags &= ~(std::uint32_t{1} << 1);
  const bool set = (flags & (std::uint32_t{1} << 3)) != 0;
  std::printf("%lu %d\n", static_cast<unsigned long>(flags), set);
}

Read and run this example in the stated environment. Code is displayed here; it does not execute in your browser.

RememberBitwise & differs from logical &&.

Practice and check your understanding

Try each question before opening the worked answer.

1. What is 0x0F AND 0x03?

Show answer and reasoning

0x03. Only the two lowest bits are set in both operands.

2. Does flags |= mask guarantee atomic access?

Show answer and reasoning

No. It is normally a read-modify-write expression. Shared data needs an appropriate atomic mechanism.

Continue learning

Technical references and further reading

References are for further study, not endorsements. Report an error or suggest an improvement.

Progress stays on this browser only. Clearing site data removes it; it does not sync across devices.