Bit Manipulation

Course 3 · Ch 1
Bit Manipulation
The lowest level of control C offers over a single value

Course 3 starts at the smallest possible unit: individual bits. c1-3 listed the bitwise operators briefly; this chapter finally uses each one deliberately, and shows what real code built on them looks like.

The Bitwise Operators, In Depth

  • & (AND) — masking: clears every bit not set in both operands
  • | (OR) — setting: turns on every bit set in either operand
  • ^ (XOR) — toggling: flips exactly the bits set in one operand but not the other
  • ~ (NOT) — inverting: flips every bit
  • <</>> (shifts) — multiply/divide by a power of two, one bit position at a time
unsigned int a = 0b1100; unsigned int b = 0b1010; a & b; // 0b1000 a | b; // 0b1110 a ^ b; // 0b0110 a << 2; // 0b110000 — multiplied by 4

Bit Flags

Packing several independent boolean flags into individual bits of one integer — a compact, historically common C idiom.

#define FLAG_A (1 << 0) #define FLAG_B (1 << 1) #define FLAG_C (1 << 2) unsigned int flags = 0; flags |= FLAG_A; // set FLAG_A flags &= ~FLAG_B; // clear FLAG_B if (flags & FLAG_A) { /* FLAG_A is set */ }

Rust typically reaches for a dedicated bitflags crate, or simply a struct of separate bool fields, rather than packing everything into one integer by hand. C's version is partly a legacy of byte-economy habits — but it's still extremely common in real-world APIs.

Bit Fields in Structs

The :N syntax packs sub-byte-width fields into fewer total bytes — genuinely useful for memory-constrained code or mapping directly onto hardware registers.

struct Status { unsigned int is_active : 1; unsigned int is_locked : 1; unsigned int priority : 6; };

A real caveat: the exact bit ordering and packing within a bit-field struct is implementation-defined — not portable across different compilers or platforms, unlike every other struct layout rule this course has relied on.

A Real Example — POSIX Open Flags

open(path, O_RDONLY | O_CREAT | O_TRUNC, mode);

The exact bit-flag idiom from this chapter, used constantly in real systems code — three independent flags OR'd together into one argument, exactly the pattern just built by hand above.

ConceptRustC
Multiple boolean flagsbitflags crate, or a struct of boolsOR-together bits in one integer
Sub-byte struct fieldsnot a language feature — hand-packed if needednative bit-field syntax (:N), but implementation-defined layout
Name every flag bit
Defining a named constant for each flag bit, rather than writing raw magic numbers, is what keeps bit-flag code readable — FLAG_A communicates intent; 1 alone does not.
Shifting too far is undefined behavior, not "shifts in zeros"
Shifting a value by an amount greater than or equal to its type's bit width — or left-shifting a negative signed value — is undefined behavior, not a harmless zero result. A 32-bit int shifted by 32 is a genuinely easy mistake to make, and Course 3's own Undefined Behavior Deep Dive covers exactly why the compiler is allowed to assume this never happens.

Coding Challenges

Challenge 1

Define three named flag constants using left-shift (FLAG_READ, FLAG_WRITE, FLAG_EXEC), combine all three into one unsigned int with OR, then check and print whether each individual flag is set using AND.

📄 View solution
Challenge 2

Starting from a flags variable with FLAG_READ and FLAG_WRITE both set, clear just FLAG_WRITE using AND with a NOT'd mask, and print the flags variable's value before and after to confirm only FLAG_WRITE was removed.

📄 View solution
Challenge 3

Explain why bit-field struct layouts are described as implementation-defined rather than fully portable, and what practical risk this creates if a bit-field struct is used to interpret data written by a different compiler or platform.

📄 View solution

Chapter 1 Quick Reference

  • & mask, | set, ^ toggle, ~ invert, <</>> shift
  • Bit flags — OR to set, AND with a NOT'd mask to clear, AND to check
  • Bit-field structs (:N) pack sub-byte fields — but layout is implementation-defined, not portable
  • POSIX open()'s flag argument is the exact bit-flag idiom, used in real systems code
  • Shifting by >= the type's bit width, or left-shifting a negative value, is undefined behavior
  • Next chapter: building data structures from scratch — a linked list and a hash table, no standard-library containers