Bitmasks & Flags
A single integer has many bits, and nothing says they all have to represent one number — each bit can instead represent an independent true/false flag. This is a bitmask: a set of boolean flags packed into one integer, combined and tested with bitwise operators instead of an array of separate booleans.
Defining flags with left-shift
The idiomatic way to define a set of flag constants is with 1 << n, so each constant has exactly one bit set, and no two flags accidentally share a bit:
#define FLAG_READ (1 << 0) // 0001 #define FLAG_WRITE (1 << 1) // 0010 #define FLAG_EXECUTE (1 << 2) // 0100 #define FLAG_HIDDEN (1 << 3) // 1000
Combining, checking, and clearing flags
Operation | How |
|---|---|
Combine flags |
|
Add a flag |
|
Check if a flag is set |
|
Clear a flag |
|
Toggle a flag |
|
Worked example: a permissions system
#include <stdio.h>
#define PERM_READ (1 << 0)
#define PERM_WRITE (1 << 1)
#define PERM_EXECUTE (1 << 2)
void print_permissions(unsigned int perms) {
printf("read=%d write=%d execute=%d\n",
(perms & PERM_READ) != 0,
(perms & PERM_WRITE) != 0,
(perms & PERM_EXECUTE) != 0);
}
int main(void) {
// Combine flags with | to build up a permission set.
unsigned int file_perms = PERM_READ | PERM_WRITE;
print_permissions(file_perms);
// Add execute permission.
file_perms |= PERM_EXECUTE;
print_permissions(file_perms);
// Revoke write permission.
file_perms &= ~PERM_WRITE;
print_permissions(file_perms);
// Check a single flag directly.
if (file_perms & PERM_READ) {
printf("file is readable\n");
}
return 0;
}read=1 write=1 execute=0 read=1 write=1 execute=1 read=1 write=0 execute=1 file is readable
Why bitmasks instead of an array of booleans
An array of eight bool values (in C, typically stored as one byte each) uses eight bytes to represent eight flags. The same eight flags packed into the bits of a single unsigned char use exactly one byte — an 8x reduction. At larger scale (thousands or millions of flag sets, as in permission systems, feature flags, or network protocol headers) this adds up to a meaningful difference in memory use, and it also lets you combine, compare, and transmit an entire set of flags with a single integer operation rather than looping over an array.
Define each flag with
1 << nso every flag occupies exactly one distinct bit.Combine flags with
|, check one with&, clear one with&= ~flag, toggle one with^.A bitmask packs many boolean flags into a single integer, using far less memory than an array of booleans.
Use an unsigned integer type wide enough to hold every flag you need, and document each bit's meaning.