Bitmask and Bitwise Operations — Flags, Permissions, and Bit Manipulation
Bitmasks store multiple boolean flags in a single integer using bitwise AND, OR, and XOR. Learn how to set, clear, and check bits for file permissions, feature flags, and game...
Use the tool
Number Base Converter
Convert between binary, octal, decimal, hexadecimal, and text (UTF-8). Handles arbitrary lengths. Per-byte and per-character views.
A bitmask uses individual bits of an integer as independent boolean flags. One 32-bit integer holds 32 independent boolean values, with O(1) set/get/clear operations.
Convert between binary and decimal with the Number Base Converter.
Bitwise operators
// AND: both bits must be 1
0b1010 & 0b1100 // 0b1000 = 8
// OR: at least one bit is 1
0b1010 | 0b1100 // 0b1110 = 14
// XOR: exactly one bit is 1 (toggle)
0b1010 ^ 0b1100 // 0b0110 = 6
// NOT: flip all bits
~0b00001111 // 0b11110000 (as 32-bit: -16)
// Left shift: multiply by powers of 2
1 << 3 // 8 (1 × 2³)
0b0001 << 2 // 0b0100 = 4
// Right shift: divide by powers of 2
16 >> 2 // 4
0b1000 >> 1 // 0b0100 = 4
Define flags with bit shifts
// Define named flags as powers of 2:
const Permission = {
NONE: 0,
READ: 1 << 0, // 0b0001 = 1
WRITE: 1 << 1, // 0b0010 = 2
EXECUTE: 1 << 2, // 0b0100 = 4
ADMIN: 1 << 3, // 0b1000 = 8
};
// Set flags: combine with OR
const userPerms = Permission.READ | Permission.WRITE;
// 0b0001 | 0b0010 = 0b0011 = 3
// Check a flag: AND with the flag
const canRead = (userPerms & Permission.READ) !== 0; // true
const canExec = (userPerms & Permission.EXECUTE) !== 0; // false
// Add a flag:
const newPerms = userPerms | Permission.EXECUTE; // 0b0111 = 7
// Remove a flag: AND with NOT of the flag
const stripped = userPerms & ~Permission.WRITE; // 0b0001 = 1
// Toggle a flag:
const toggled = userPerms ^ Permission.WRITE; // 0b0001 = 1 (removes WRITE)
Practical example: Unix file permissions
// Unix rwxrwxrwx permissions:
const PERM = {
OWNER_READ: 0o400, // 256
OWNER_WRITE: 0o200, // 128
OWNER_EXEC: 0o100, // 64
GROUP_READ: 0o040, // 32
GROUP_WRITE: 0o020, // 16
GROUP_EXEC: 0o010, // 8
OTHERS_READ: 0o004, // 4
OTHERS_WRITE: 0o002, // 2
OTHERS_EXEC: 0o001, // 1
};
// chmod 644 = rw-r--r--
const permissions = PERM.OWNER_READ | PERM.OWNER_WRITE |
PERM.GROUP_READ | PERM.OTHERS_READ;
// = 0o644 = 420
// Check if owner can write:
(permissions & PERM.OWNER_WRITE) !== 0; // true
// Convert to rwxrwxrwx string:
function permsToString(p) {
return [
[PERM.OWNER_READ, 'r'], [PERM.OWNER_WRITE, 'w'], [PERM.OWNER_EXEC, 'x'],
[PERM.GROUP_READ, 'r'], [PERM.GROUP_WRITE, 'w'], [PERM.GROUP_EXEC, 'x'],
[PERM.OTHERS_READ, 'r'], [PERM.OTHERS_WRITE, 'w'], [PERM.OTHERS_EXEC, 'x'],
].map(([flag, ch]) => (p & flag) ? ch : '-').join('');
}
permsToString(0o644); // "rw-r--r--"
Feature flags with bitmasks
// Store multiple feature toggles in one integer (useful in cookies/URLs):
const Features = {
DARK_MODE: 1 << 0, // 1
BETA_EDITOR: 1 << 1, // 2
AI_SUGGESTIONS: 1 << 2, // 4
NEW_DASHBOARD: 1 << 3, // 8
};
// User with dark mode + AI suggestions enabled:
const userFeatures = Features.DARK_MODE | Features.AI_SUGGESTIONS;
// = 0b0101 = 5
// Store in cookie as single integer:
document.cookie = `features=${userFeatures}`;
// Check feature:
const isDarkMode = (userFeatures & Features.DARK_MODE) !== 0;
Python bitmasks
# Define flags:
from enum import IntFlag
class Permission(IntFlag):
NONE = 0
READ = 1 << 0
WRITE = 1 << 1
EXECUTE = 1 << 2
ADMIN = 1 << 3
# IntFlag supports all bitwise operations naturally:
user_perms = Permission.READ | Permission.WRITE
# Permission.READ|WRITE
user_perms & Permission.ADMIN # Permission(0) — falsy
user_perms & Permission.READ # Permission.READ — truthy
# Check which flags are set:
for perm in Permission:
if perm in user_perms:
print(f"{perm.name}: enabled")
# READ: enabled
# WRITE: enabled
Bit manipulation tricks
// Check if number is a power of 2:
function isPowerOfTwo(n) {
return n > 0 && (n & (n - 1)) === 0;
}
isPowerOfTwo(64); // true (64 = 0b01000000)
isPowerOfTwo(48); // false (48 = 0b00110000)
// Isolate the lowest set bit:
function lowestBit(n) {
return n & (-n);
}
lowestBit(0b10110); // 0b00010 = 2
// Count set bits (popcount):
function popcount(n) {
let count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
return count;
}
popcount(0b10110); // 3
// Round up to nearest power of 2:
function nextPowerOfTwo(n) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
nextPowerOfTwo(100); // 128
RGB color packing
// Pack R, G, B into a 32-bit integer:
function packRGB(r, g, b) {
return (r << 16) | (g << 8) | b;
}
function unpackRGB(packed) {
return {
r: (packed >> 16) & 0xFF,
g: (packed >> 8) & 0xFF,
b: packed & 0xFF,
};
}
const color = packRGB(255, 128, 0); // 0xFF8000 = orange
unpackRGB(color); // { r: 255, g: 128, b: 0 }
Related tools
- Number Base Converter — convert hex/binary/decimal
- Binary Arithmetic Guide — addition and two’s complement
- Hash Generator — bitwise operations in cryptographic hashing
Related posts
- Binary Arithmetic — Addition, Subtraction, and Two's Complement — Learn how computers perform binary arithmetic: binary addition with carry, two's…
- Binary to Decimal — Convert Binary Numbers the Right Way — Binary to decimal conversion is foundational to understanding how computers stor…
- Binary to Text: How Binary Numbers Represent Characters — Binary to text conversion isn't magic — it's a lookup table. ASCII, Unicode, UTF…
Related tool
Number Base Converter
Convert between binary, octal, decimal, hexadecimal, and text (UTF-8). Handles arbitrary lengths. Per-byte and per-character views.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.