Every time you type chmod 755, a TCP packet arrives at your network card, or you press a button on a game controller, bit flags are doing the work. A bit flag is a single bit that represents a boolean condition. A bitmask is a group of bit flags packed into one integer. The idea is simple — each bit position means something — but the implications are massive: eight booleans fit in one byte instead of eight, a game engine tracks 32 input states in a single register read, and a TCP header encodes 9 control flags in 16 bits of overhead. Here is how to design and use them.
How Bit Flags Work
Assign each flag a power of two — this guarantees each flag occupies a unique bit position with no overlap. Use 1 << n to define them so the position is visible in the code rather than a magic number.
// Define 8 flags, each in its own bit position
#define FLAG_READ (1 << 0) // 0b00000001 = 1
#define FLAG_WRITE (1 << 1) // 0b00000010 = 2
#define FLAG_EXECUTE (1 << 2) // 0b00000100 = 4
#define FLAG_DELETE (1 << 3) // 0b00001000 = 8
#define FLAG_SHARE (1 << 4) // 0b00010000 = 16
#define FLAG_OWNER (1 << 5) // 0b00100000 = 32
#define FLAG_HIDDEN (1 << 6) // 0b01000000 = 64
#define FLAG_SYSTEM (1 << 7) // 0b10000000 = 128
// 8 flags, 8 bits — exactly one byte
uint8_t permissions = 0; // all flags off initially
Use our bit mask calculator to generate masks for any set of bit positions — enter the bit numbers and get the combined mask value in binary, hex, and decimal instantly.
The Four Operations on Bit Flags
| Operation | Operator | Pattern | Effect |
|---|---|---|---|
| Set | OR | flags |= MASK | Turns specific bits ON, leaves others unchanged |
| Check | AND | flags & MASK | Returns non-zero if ANY masked bit is 1 |
| Clear | AND + NOT | flags &= ~MASK | Turns specific bits OFF, leaves others unchanged |
| Toggle | XOR | flags ^= MASK | Flips specific bits, inverts their state |
// All four operations on a single flags variable
permissions |= FLAG_READ; // Set: grant read
permissions |= (FLAG_WRITE | FLAG_EXECUTE); // Set multiple: grant write+execute
if (permissions & FLAG_WRITE) { // Check: can this user write?
write_to_file();
}
permissions &= ~FLAG_EXECUTE; // Clear: revoke execute
permissions ^= FLAG_HIDDEN; // Toggle: flip hidden state
Every flag operation is one CPU instruction and one line of code. No allocations, no branches, no hash lookups. This is why bit flags are the default choice for permission systems, feature gates, and hardware control registers. Try these patterns on our bit flags calculator to see each operation's effect on the binary representation.
Real Example 1: Linux File Permissions (rwx)
The Unix permission model is the most recognizable bit flag system in computing. Three categories (owner, group, others) each have three flags (read, write, execute). Nine bits total, packed into the lower 9 bits of the file mode.
// Linux file permission flags (from sys/stat.h)
#define S_IRUSR 00400 // owner read (bit 8)
#define S_IWUSR 00200 // owner write (bit 7)
#define S_IXUSR 00100 // owner execute (bit 6)
#define S_IRGRP 00040 // group read (bit 5)
#define S_IWGRP 00020 // group write (bit 4)
#define S_IXGRP 00010 // group execute (bit 3)
#define S_IROTH 00004 // other read (bit 2)
#define S_IWOTH 00002 // other write (bit 1)
#define S_IXOTH 00001 // other execute (bit 0)
// chmod 754 in code:
mode_t mode = S_IRWXU // owner: rwx (7)
| S_IRGRP | S_IXGRP // group: r-x (5)
| S_IROTH; // other: r-- (4)
// Check if anyone can write:
if (mode & S_IWUSR) printf("owner can write\n");
if (mode & S_IWGRP) printf("group can write\n");
if (mode & S_IWOTH) printf("others can write\n");
// chmod 754 → only "owner can write" prints
The octal notation (0754) is not an accident — each digit maps directly to 3 bits (rwx), which is exactly one octal digit. 7 = 111 (rwx), 5 = 101 (r-x), 4 = 100 (r--). The entire Unix permission model is a bit flag system with octal shorthand.
Real Example 2: TCP Header Flags
Every TCP segment carries a 9-bit flags field that controls the connection state machine. SYN opens connections, ACK acknowledges data, FIN closes gracefully, RST aborts — all packed into a single 16-bit field (flags occupy bits 0-8, with bit 9 reserved).
// TCP header control flags (RFC 793)
#define TCP_FIN (1 << 0) // 0x001: Finish — no more data from sender
#define TCP_SYN (1 << 1) // 0x002: Synchronize — initiate connection
#define TCP_RST (1 << 2) // 0x004: Reset — abort connection
#define TCP_PSH (1 << 3) // 0x008: Push — send data immediately
#define TCP_ACK (1 << 4) // 0x010: Acknowledgment — confirms receipt
#define TCP_URG (1 << 5) // 0x020: Urgent — prioritize this segment
#define TCP_ECE (1 << 6) // 0x040: ECN Echo — congestion notification
#define TCP_CWR (1 << 7) // 0x080: Congestion Window Reduced
#define TCP_NS (1 << 8) // 0x100: ECN Nonce Sum
// The TCP three-way handshake in flags:
// Client → Server: SYN
// Server → Client: SYN | ACK
// Client → Server: ACK
// Connection established — three packets, 9 possible flags, zero wasted bits.
Wireshark and tcpdump decode these flags every time you capture a packet. The compact encoding means 9 control signals travel in just 2 bytes of overhead — essential when every byte of header space matters for throughput.
Real Example 3: Game Engine Input State
Game engines poll controller input every frame — often at 60 or 120 FPS. Storing each button as a separate boolean wastes memory and CPU cache. A single 32-bit integer tracks all buttons simultaneously, and checking whether "jump is pressed" is one AND instruction.
// Joystick / gamepad button flags (XInput-style)
#define BTN_DPAD_UP (1 << 0)
#define BTN_DPAD_DOWN (1 << 1)
#define BTN_DPAD_LEFT (1 << 2)
#define BTN_DPAD_RIGHT (1 << 3)
#define BTN_START (1 << 4)
#define BTN_SELECT (1 << 5)
#define BTN_L3 (1 << 6) // left stick click
#define BTN_R3 (1 << 7) // right stick click
#define BTN_L1 (1 << 8) // left bumper
#define BTN_R1 (1 << 9) // right bumper
#define BTN_A (1 << 12) // cross / A
#define BTN_B (1 << 13) // circle / B
#define BTN_X (1 << 14) // square / X
#define BTN_Y (1 << 15) // triangle / Y
uint32_t buttons = poll_controller();
// Frame update: check multiple inputs simultaneously
bool is_jumping = buttons & BTN_A; // one AND
bool is_crouching = buttons & BTN_B; // same variable, different bit
bool is_shooting = buttons & BTN_R1; // still one instruction each
// Check combo: jump + shoot + dodge
bool super_move = (buttons & (BTN_A | BTN_R1 | BTN_L1)) == (BTN_A | BTN_R1 | BTN_L1);
Notice the gap between bits 9 and 12 — this is common when flags are grouped by meaning or hardware layout. The unused bits cost nothing and make the code self-documenting. The entire controller state fits in a single 32-bit register and can be copied with one mov instruction.
Real Example 4: Text Rendering Style Flags
Font rendering engines — FreeType, DirectWrite, CoreText — all use bit flags for style attributes. Bold, italic, underline, strikethrough, small caps, superscript, and more can all be combined into a single style integer.
// Text rendering style flags
typedef enum {
STYLE_NORMAL = 0,
STYLE_BOLD = 1 << 0, // 0x001
STYLE_ITALIC = 1 << 1, // 0x002
STYLE_UNDERLINE = 1 << 2, // 0x004
STYLE_STRIKETHROUGH = 1 << 3, // 0x008
STYLE_SMALL_CAPS = 1 << 4, // 0x010
STYLE_SUPERSCRIPT = 1 << 5, // 0x020
STYLE_SUBSCRIPT = 1 << 6, // 0x040
STYLE_MONOSPACE = 1 << 7, // 0x080
} TextStyle;
// Combine styles for rich text
TextStyle heading = STYLE_BOLD | STYLE_ITALIC; // 0x003
TextStyle code = STYLE_MONOSPACE; // 0x080
TextStyle deleted = STYLE_STRIKETHROUGH | STYLE_ITALIC; // 0x00A
// Fast check when laying out text
if (style & STYLE_BOLD) {
select_bold_typeface();
}
// No string comparisons, no enum switch — just bit tests
This pattern appears in CSS engines (parsing font-weight and font-style into internal flags), terminal emulators (ANSI SGR codes map directly to style bit flags), and rich text editors. One integer replaces 8 separate boolean fields — 1 byte versus 8 in the struct, or 4 versus 32 on the stack.
Why Bit Flags Win
Memory: One 32-bit integer holds 32 independent boolean flags. A struct with 32 bool fields takes at least 32 bytes — an 8x difference. In a game engine processing thousands of entities per frame, that is the difference between fitting in L1 cache and spilling to L2. Speed: Checking a flag is one AND instruction — 1 clock cycle. Passing flags to a function copies one register, not a struct. Atomicity: Reading or writing a 32-bit integer is atomic on all modern CPUs. You cannot read a half-updated set of bits, unlike a struct where one thread writes while another reads.
The patterns in this article — define with 1 << n, set with OR, check with AND, clear with AND+NOT, toggle with XOR — are identical across C, C++, Rust, Go, Python, JavaScript, and every language that supports bitwise operators. Master them once and use them everywhere. Build and test your own bit flags with our bit flags calculator and bit mask calculator, or explore the complete bitwise operations guide.