C++ PROGRAMMING · 13 MIN STUDY

Bit manipulation and bit flags

Use bitwise operators to inspect, set, clear, and toggle individual flags.

Learning objectives

  • Read binary representations of small unsigned integers.
  • Use AND, OR, XOR, NOT, and shifts for bit flags.
  • Set, clear, test, and toggle a bit.
  • Avoid unsafe shift and signed-integer assumptions.

Prerequisites: be comfortable with integer variables, binary place values, and basic arithmetic. The lesson introduces bitwise operators, but understanding powers of two will make the examples easier.

Bits and binary

Binary represents a value using bits: each position is a power of two. For example, the unsigned value 5 is binary 0101 in a four-bit illustration. Bitwise operations work on these positions rather than treating the whole value as true or false.

Set, test, clear, toggle

Suppose a bit mask uses one bit per option. Create a mask by shifting an unsigned value:

constexpr unsigned int READ  = 1u << 0;
constexpr unsigned int WRITE = 1u << 1;
constexpr unsigned int EXEC  = 1u << 2;
  • Set a flag: flags |= WRITE;
  • Test a flag: (flags & WRITE) != 0
  • Clear a flag: flags &= ~WRITE;
  • Toggle a flag: flags ^= WRITE;

Worked example

Each named mask gives one bit a readable name. Here, READ is 0001, WRITE is 0010, and EXEC is 0100 in a four-bit illustration. OR combines selected bits; it does not erase flags that are already set.

C++17
#include <iostream>

int main() {
    constexpr unsigned int READ = 1u << 0;
    constexpr unsigned int WRITE = 1u << 1;
    constexpr unsigned int EXEC = 1u << 2;

    unsigned int flags{};
    flags |= READ;
    flags |= WRITE;
    std::cout << flags << '\n'; // 3: READ and WRITE

    if ((flags & READ) != 0) {
        std::cout << "read enabled\n";
    }

    flags &= ~WRITE;
    flags ^= EXEC;
    std::cout << flags << '\n'; // 5: READ and EXEC
}

Trace: start at 0000; set READ and WRITE to get 0011 (decimal 3); clear WRITE to get 0001; toggle EXEC to get 0101 (decimal 5). The output is 3, read enabled, then 5.

Shift safety

Use unsigned types for bit masks. Before shifting, ensure the count is non-negative and smaller than the width of the promoted left operand; a negative count or a count greater than or equal to that width has undefined behavior. Integer promotions matter: a small integer type such as unsigned char is promoted before the shift. The 1u literal makes the mask's starting value unsigned. Signed shifts have additional rules, so prefer unsigned operands for bit masks.

Where bit flags are useful

Bit flags are useful when several independent on/off options must be stored or passed together—for example, file permissions, feature settings, protocol options, and compact status fields. Use named masks rather than unexplained numeric literals so each bit's meaning stays clear.

Common mistakes

  • Using logical && instead of bitwise &.
  • Using signed integers for masks without understanding the rules.
  • Shifting by the width of the promoted left operand or more.
  • Clearing a flag with flags &= WRITE instead of the complement mask.

Practice

  1. Define three permission flags and combine two of them.
  2. Test whether a flag is enabled.
  3. Clear one flag without changing the others.
  4. Draw the binary result of setting and clearing a bit in a small unsigned value.

Practice solutions

Show worked solutions
  1. Combine flags with bitwise OR: unsigned flags = READ | WRITE;. OR sets each selected bit without clearing other bits.
  2. Test a flag with (flags & READ) != 0. The bitwise AND result is nonzero when that bit is set.
  3. Clear a flag with flags &= ~WRITE;. The complemented mask has zero in the WRITE position and ones elsewhere.
  4. For an eight-bit illustration, start with 0000 0101 (bits 2 and 0 set). Clearing bit 2 gives 0000 0001; setting bit 1 then gives 0000 0011. Use an unsigned type and ensure every shift count is smaller than the width of the promoted left operand.

Check your understanding

Which operation sets a flag without changing other bits?

Answer: Bitwise OR assignment: flags |= mask;.

Summary

Bit masks represent several Boolean flags inside an integer. Use OR to set, AND to test or clear, XOR to toggle, and unsigned operands with valid shift counts.

References