Bit Flags and Bitmasks

Pack 8 boolean options into a single byte — how the software you use every day saves memory and bandwidth

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

OperationOperatorPatternEffect
SetORflags |= MASKTurns specific bits ON, leaves others unchanged
CheckANDflags & MASKReturns non-zero if ANY masked bit is 1
ClearAND + NOTflags &= ~MASKTurns specific bits OFF, leaves others unchanged
ToggleXORflags ^= MASKFlips 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.