Data Representation: Bits, Bytes & Numbers

masking and bit flags

Often you want to pack many tiny yes/no settings into one number — is this file readable? writable? hidden? — rather than spending a whole separate variable on each. A single 32-bit integer has room for 32 independent on/off switches, one per bit. To use them you need two ideas working together: a bit flag (one bit standing for one option) and a mask (a carefully chosen pattern that selects which bits you want to act on).

A mask is just a value whose 1 bits mark the positions of interest, and combining it with a bitwise operator lets you do the four basic bit operations cleanly. To TEST whether a bit is set, AND with a mask that has a 1 only there and check if the result is nonzero: (x & 0x04) is nonzero exactly when bit 2 of x is set. To SET a bit (force it to 1), OR with the mask: x = x | 0x04. To CLEAR a bit (force it to 0), AND with the INVERTED mask: x = x & ~0x04. To TOGGLE a bit (flip it), XOR with the mask: x = x ^ 0x04. By convention each flag gets a name, often defined as a power of two so it occupies exactly one bit, and several flags are combined with OR — for example open() takes flags like O_RDONLY, O_CREAT, O_APPEND ORed together into one argument.

This pattern is everywhere in systems programming: file permissions, open() and mmap() option flags, hardware register bits, event masks, and compact data formats all rely on it. Two pitfalls to keep in mind. First, define each flag as a distinct power of two (1, 2, 4, 8, ...) so no two flags share a bit; accidentally reusing a bit makes flags interfere. Second, remember operator precedence: the bitwise operators bind more loosely than comparison, so 'x & 0x04 == 0' is parsed as 'x & (0x04 == 0)', which is almost never what you want — parenthesize as '(x & 0x04) == 0'.

Test bit 2: if (x & 0x04) ... ; set it: x |= 0x04; clear it: x &= ~0x04; toggle it: x ^= 0x04. Combine flags for open(): open(path, O_WRONLY | O_CREAT | O_APPEND, 0644).

AND to test/clear, OR to set, XOR to toggle.

Because '&' has lower precedence than '==', write '(x & MASK) == 0', not 'x & MASK == 0' (which means 'x & (MASK == 0)'); and define each flag as a separate power of two so flags never collide on a shared bit.

Also called
bit maskbitfield flagsset/clear/toggle/test a bit位元遮罩位元旗標