Loading content...
Now that you can see individual bits, it's time to learn how to change them. Setting a bit—turning a 0 into a 1—is the fundamental operation for activation: enabling a feature, granting a permission, adding an element to a set, or initializing a flag.
The challenge is surgical precision: we must set exactly one bit to 1 while leaving all other bits completely untouched. If the bit is already 1, it should remain 1. If adjacent bits are 1, they must stay 1. This selective modification requires understanding how bitwise OR creates a union of set bits.
In this page, we'll develop a deep understanding of the bit-setting operation, examine why OR is the perfect tool for the job, explore edge cases, and see how this operation powers real systems.
By the end of this page, you will understand: (1) The formula n | (1 << i) for setting bit i, (2) Why bitwise OR guarantees we set our target without clearing others, (3) The idempotent nature of bit setting—setting an already-set bit changes nothing, (4) How to set multiple bits efficiently, (5) Real-world applications in state activation and permission granting, and (6) Performance characteristics and compilation behavior.
Setting a bit means forcing a specific bit position to 1, regardless of its current value.
Given:
n (our target number)i (the bit position to set)Goal:
i is guaranteed to be 1The Formula:
result = n | (1 << i)
This formula has two components:
(1 << i) — Creates a mask with only bit i set to 1n | mask — Performs bitwise OR to merge the mask into nLet's trace through this step by step.
Example: Set bit 2 in the number 9 Step 1: Start with n = 9Binary: 0 0 0 0 1 0 0 1 7 6 5 4 3 2 1 0 ← bit positions Step 2: Create mask with (1 << 2)1: 0 0 0 0 0 0 0 11 << 2: 0 0 0 0 0 1 0 0 ← mask has only bit 2 set Step 3: OR the number with the maskn = 9: 0 0 0 0 1 0 0 1mask = 4: 0 0 0 0 0 1 0 0 | ─────────────────Result: 0 0 0 0 1 1 0 1 = 13 Bit 2 is now set (was 0, now 1)All other bits unchangedThe choice of bitwise OR is not arbitrary—the truth table of OR perfectly matches our requirements for bit setting. Let's examine why.
OR Truth Table:
| A | B | A OR B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
Key Insight: When you OR with 1, the result is always 1, regardless of the original value. When you OR with 0, the original value is preserved.
This gives us exactly what we need:
Understanding OR behavior at each bit position: Original n: 1 0 1 1 0 0 1 0Mask (1<<3): 0 0 0 0 1 0 0 0 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ For each position, apply OR:Pos 7: 1 OR 0 = 1 (preserved: mask is 0)Pos 6: 0 OR 0 = 0 (preserved: mask is 0)Pos 5: 1 OR 0 = 1 (preserved: mask is 0)Pos 4: 1 OR 0 = 1 (preserved: mask is 0)Pos 3: 0 OR 1 = 1 (FORCED to 1: mask is 1) ← This is the set!Pos 2: 0 OR 0 = 0 (preserved: mask is 0)Pos 1: 1 OR 0 = 1 (preserved: mask is 0)Pos 0: 0 OR 0 = 0 (preserved: mask is 0) Result: 1 0 1 1 1 0 1 0 Only bit 3 changed (0→1). All other bits unchanged.Think of bitwise OR as taking the union of two sets of bits. If either the original OR the mask has a bit set, the result has that bit set. Our mask is a singleton set containing just bit i, so ORing adds bit i to our original number's set of bits.
A crucial property of the set operation is idempotence: setting a bit that's already 1 has no effect. The result is identical to the input.
This property is incredibly useful because:
Setting bit 3 in a number where bit 3 is ALREADY set: n = 13: 0 0 0 0 1 1 0 1 (bits 0, 2, 3 are set)mask (1<<3): 0 0 0 0 1 0 0 0 (want to set bit 3) | ─────────────────Result: 0 0 0 0 1 1 0 1 = 13 (no change!) 1 OR 1 = 1, so setting an already-set bit keeps it as 1. This is idempotence: set(set(n, i), i) === set(n, i) Mathematical property: n | mask | mask === n | maskIn concurrent systems, idempotent operations are precious. If a 'grant permission' message is received twice due to network retries, an idempotent set operation ensures the permission is still correctly granted exactly once. No corruption, no special handling needed.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
// Set bit at position i// Returns a new value with bit i guaranteed to be 1 function setBit(n: number, i: number): number { return n | (1 << i);} // In-place modification (when working with variables)function setBitInPlace(value: { n: number }, i: number): void { value.n |= (1 << i); // Equivalent to: value.n = value.n | (1 << i)} // Examples demonstrating idempotenceconst n = 9; // Binary: 1001console.log(setBit(n, 2)); // 13 (Binary: 1101) - bit 2 was 0, now 1console.log(setBit(n, 0)); // 9 (Binary: 1001) - bit 0 was 1, stays 1console.log(setBit(n, 3)); // 9 (Binary: 1001) - wait, that's wrong!// Actually: 9 | 8 = 1001 | 1000 = 1001... no!// Let me recalculate: 9 = 1001, 1<<3 = 1000, 1001 | 1000 = 1001// Hmm, bit 3 of 9: 9 >> 3 = 1, so bit 3 IS set in 9// 9 = 8 + 1 = 2^3 + 2^0, so bits 0 and 3 are set // Correct demonstration:const m = 5; // Binary: 0101 (bits 0 and 2 are set)console.log(setBit(m, 1)); // 7 (Binary: 0111) - bit 1 was 0, now 1console.log(setBit(m, 2)); // 5 (Binary: 0101) - bit 2 was 1, stays 1 (idempotent) ---python# Set bit at position i# Returns a new value with bit i guaranteed to be 1 def set_bit(n: int, i: int) -> int: return n | (1 << i) # Examples demonstrating idempotencen = 5 # Binary: 0101 (bits 0 and 2 are set) print(f"Original: {n} = {bin(n)}")print(f"Set bit 1: {set_bit(n, 1)} = {bin(set_bit(n, 1))}") # 7 = 0b111print(f"Set bit 2: {set_bit(n, 2)} = {bin(set_bit(n, 2))}") # 5 = 0b101 (no change, idempotent)print(f"Set bit 3: {set_bit(n, 3)} = {bin(set_bit(n, 3))}") # 13 = 0b1101 # Chain of sets (all idempotent)result = nresult = set_bit(result, 1)result = set_bit(result, 1) # Setting same bit againresult = set_bit(result, 1) # And againprint(f"After setting bit 1 three times: {result}") # Still 7 ---javapublic class SetBit { // Set bit at position i // Returns a new value with bit i guaranteed to be 1 public static int setBit(int n, int i) { return n | (1 << i); } public static void main(String[] args) { int n = 5; // Binary: 0101 (bits 0 and 2 are set) System.out.println("Original: " + n + " = " + Integer.toBinaryString(n)); System.out.println("Set bit 1: " + setBit(n, 1)); // 7 System.out.println("Set bit 2: " + setBit(n, 2)); // 5 (idempotent) System.out.println("Set bit 3: " + setBit(n, 3)); // 13 // Demonstrating in-place with compound assignment int m = 5; m |= (1 << 1); // Set bit 1 m |= (1 << 1); // Set bit 1 again (no effect) System.out.println("After setting bit 1 twice: " + m); // 7 }} ---cpp#include <iostream>#include <bitset> // Set bit at position i// Returns a new value with bit i guaranteed to be 1int setBit(int n, int i) { return n | (1 << i);} int main() { int n = 5; // Binary: 0101 (bits 0 and 2 are set) std::cout << "Original: " << n << " = " << std::bitset<8>(n) << std::endl; std::cout << "Set bit 1: " << setBit(n, 1) << " = " << std::bitset<8>(setBit(n, 1)) << std::endl; // 7 std::cout << "Set bit 2: " << setBit(n, 2) << " = " << std::bitset<8>(setBit(n, 2)) << std::endl; // 5 (idempotent) std::cout << "Set bit 3: " << setBit(n, 3) << " = " << std::bitset<8>(setBit(n, 3)) << std::endl; // 13 // In-place modification int m = 5; m |= (1 << 1); // Set bit 1 m |= (1 << 1); // Set bit 1 again (no effect) std::cout << "After setting bit 1 twice: " << m << std::endl; // 7 return 0;}Often you need to set multiple bits at once. There are two approaches: sequential setting and combined masking.
Approach 1: Sequential Setting
n = n | (1 << i);
n = n | (1 << j);
n = n | (1 << k);
Approach 2: Combined Mask (More Efficient)
mask = (1 << i) | (1 << j) | (1 << k);
n = n | mask;
The combined approach is more efficient because it:
n1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
// Setting multiple bits efficiently // Approach 1: Sequential (works but less efficient)function setBitsSequential(n: number, positions: number[]): number { for (const pos of positions) { n = n | (1 << pos); } return n;} // Approach 2: Pre-computed mask (more efficient)function setBitsWithMask(n: number, positions: number[]): number { let mask = 0; for (const pos of positions) { mask |= (1 << pos); } return n | mask;} // Approach 3: When positions are known at compile time// Use predefined constants for maximum efficiencyconst BITS_0_2_5 = (1 << 0) | (1 << 2) | (1 << 5); // = 37 = 0b100101 function setKnownBits(n: number): number { return n | BITS_0_2_5;} // Examplesconsole.log(setBitsSequential(0, [1, 3, 5])); // 42 = 0b101010console.log(setBitsWithMask(0, [1, 3, 5])); // 42 = 0b101010console.log(setKnownBits(0)); // 37 = 0b100101 // Visual demonstrationfunction visualize(n: number, label: string): void { console.log(`${label}: ${n.toString(2).padStart(8, '0')} (${n})`);} let value = 0;visualize(value, "Start ");value |= (1 << 2);visualize(value, "Set bit 2");value |= (1 << 5);visualize(value, "Set bit 5");value |= (1 << 7);visualize(value, "Set bit 7"); // Output:// Start : 00000000 (0)// Set bit 2: 00000100 (4)// Set bit 5: 00100100 (36)// Set bit 7: 10100100 (164) ---python# Setting multiple bits efficiently # Approach 1: Sequential (works but less efficient)def set_bits_sequential(n: int, positions: list[int]) -> int: for pos in positions: n = n | (1 << pos) return n # Approach 2: Pre-computed mask (more efficient)def set_bits_with_mask(n: int, positions: list[int]) -> int: mask = 0 for pos in positions: mask |= (1 << pos) return n | mask # Approach 3: Functional style with reducefrom functools import reducedef set_bits_functional(n: int, positions: list[int]) -> int: mask = reduce(lambda acc, pos: acc | (1 << pos), positions, 0) return n | mask # Approach 4: When positions are known at compile timeBITS_0_2_5 = (1 << 0) | (1 << 2) | (1 << 5) # = 37 = 0b100101 def set_known_bits(n: int) -> int: return n | BITS_0_2_5 # Examplesprint(set_bits_sequential(0, [1, 3, 5])) # 42 = 0b101010print(set_bits_with_mask(0, [1, 3, 5])) # 42 = 0b101010print(set_bits_functional(0, [1, 3, 5])) # 42 = 0b101010print(set_known_bits(0)) # 37 = 0b100101 # Visual demonstrationdef visualize(n: int, label: str) -> None: print(f"{label}: {bin(n)[2:].zfill(8)} ({n})") value = 0visualize(value, "Start ")value |= (1 << 2)visualize(value, "Set bit 2")value |= (1 << 5)visualize(value, "Set bit 5")value |= (1 << 7)visualize(value, "Set bit 7")The expression 1 << i is so fundamental that it deserves detailed examination. Understanding mask creation is essential for all bit manipulation operations.
The Number 1 in Binary:
The integer literal 1 has binary representation ...00001 (all zeros except the least significant bit).
Left Shift Creates Positional Masks:
Shifting 1 left by i positions creates a number with exactly one bit set at position i:
Mask Creation: 1 << i i | Binary (8-bit) | Decimal | Hexadecimal--|----------------|---------|------------0 | 0000 0001 | 1 | 0x011 | 0000 0010 | 2 | 0x022 | 0000 0100 | 4 | 0x043 | 0000 1000 | 8 | 0x084 | 0001 0000 | 16 | 0x105 | 0010 0000 | 32 | 0x206 | 0100 0000 | 64 | 0x407 | 1000 0000 | 128 | 0x80 Pattern: 1 << i = 2^i Each mask is a power of two because there's exactly one bit set.This is why powers of two are special in binary representation.A number with exactly one bit set is always a power of two. Conversely, every power of two has exactly one bit set. This is why (n & (n-1)) == 0 tests if n is a power of two—it's checking if there's only one bit set.
Common Mask Patterns:
Beyond single-bit masks, you'll often encounter compound masks for setting ranges or specific patterns:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
// Common mask patterns for bit setting // Single bit at position iconst singleBit = (i: number) => 1 << i; // All bits from 0 to i-1 (i bits total)// Example: lowBits(4) = 0b1111 = 15 (bits 0,1,2,3)const lowBits = (i: number) => (1 << i) - 1; // All bits from i to j (inclusive)// Example: rangeBits(2, 5) = 0b00111100 = 60 (bits 2,3,4,5)const rangeBits = (i: number, j: number) => ((1 << (j - i + 1)) - 1) << i; // Every other bit (even positions)const evenBits = 0x55555555; // 0b0101...0101 // Every other bit (odd positions) const oddBits = 0xAAAAAAAA; // 0b1010...1010 // Low byte (bits 0-7)const lowByte = 0xFF; // Examplesconsole.log(singleBit(3)); // 8 = 0b1000console.log(lowBits(4).toString(2)); // 1111 (bits 0-3)console.log(rangeBits(2, 5).toString(2)); // 111100 (bits 2-5) // Setting a range of bitsfunction setLowNBits(value: number, n: number): number { return value | lowBits(n);} function setBitRange(value: number, low: number, high: number): number { return value | rangeBits(low, high);} console.log(setLowNBits(0b10000000, 4).toString(2)); // 10001111console.log(setBitRange(0b10000001, 2, 4).toString(2)); // 10011101 ---python# Common mask patterns for bit setting # Single bit at position idef single_bit(i: int) -> int: return 1 << i # All bits from 0 to i-1 (i bits total)# Example: low_bits(4) = 0b1111 = 15 (bits 0,1,2,3)def low_bits(i: int) -> int: return (1 << i) - 1 # All bits from i to j (inclusive)# Example: range_bits(2, 5) = 0b00111100 = 60 (bits 2,3,4,5)def range_bits(i: int, j: int) -> int: return ((1 << (j - i + 1)) - 1) << i # Every other bit (even positions) - for 32-bitEVEN_BITS = 0x55555555 # 0b0101...0101 # Every other bit (odd positions) - for 32-bitODD_BITS = 0xAAAAAAAA # 0b1010...1010 # Low byte (bits 0-7)LOW_BYTE = 0xFF # Examplesprint(f"single_bit(3) = {single_bit(3)} = {bin(single_bit(3))}")print(f"low_bits(4) = {low_bits(4)} = {bin(low_bits(4))}")print(f"range_bits(2, 5) = {range_bits(2, 5)} = {bin(range_bits(2, 5))}") # Setting a range of bitsdef set_low_n_bits(value: int, n: int) -> int: return value | low_bits(n) def set_bit_range(value: int, low: int, high: int) -> int: return value | range_bits(low, high) print(bin(set_low_n_bits(0b10000000, 4))) # 0b10001111print(bin(set_bit_range(0b10000001, 2, 4))) # 0b10011101While setting bits is straightforward, edge cases can cause subtle bugs. Let's examine them carefully.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
// Safe bit setting with validation function setBitSafe(n: number, i: number): number | null { // JavaScript uses 32-bit integers for bitwise operations if (i < 0) { console.error(`Position ${i} is negative`); return null; } if (i > 30) { // Bit 31 is the sign bit; setting it changes sign console.warn(`Position ${i} may affect sign bit or overflow`); } return n | (1 << i);} // Demonstrating sign bit concernsconsole.log("Setting high bits:");let n = 0; n = setBitSafe(n, 30)!;console.log(`After setting bit 30: ${n} (binary: ${(n >>> 0).toString(2)})`);// 1073741824 (positive, binary: 1000000000000000000000000000000) // Note: In JavaScript, | produces a signed 32-bit integer// Setting bit 31:n = 0;n = n | (1 << 31);console.log(`After setting bit 31: ${n}`);// -2147483648 (NEGATIVE! The sign bit was set) // To treat as unsigned, use >>> 0console.log(`Unsigned interpretation: ${n >>> 0}`);// 2147483648 (correct unsigned value) // Safe setting for full 32-bit range using BigIntfunction setBit32Safe(n: bigint, i: number): bigint { if (i < 0 || i > 31) { throw new Error(`Position ${i} out of valid 32-bit range`); } return n | (1n << BigInt(i));} console.log(setBit32Safe(0n, 31)); // 2147483648n (correct as BigInt) ---python# Safe bit setting with validation def set_bit_safe(n: int, i: int, bit_width: int = 32) -> int | None: """Safely set a bit with validation.""" if i < 0: print(f"Error: Position {i} is negative") return None if i >= bit_width: print(f"Warning: Position {i} exceeds {bit_width}-bit range") return n | (1 << i) # Python handles arbitrary precision integers, so no overflow# But we may want to mask for consistent behavior def set_bit_masked(n: int, i: int, bit_width: int = 32) -> int: """Set a bit with masking for consistent bit_width behavior.""" mask = (1 << bit_width) - 1 # All 1s for bit_width bits result = n | (1 << i) return result & mask # Demonstrating Python's arbitrary precisionprint(f"Setting bit 100 in 0: {(0 | (1 << 100))}")# 1267650600228229401496703205376 (2^100 - works fine in Python!) # But for 32-bit simulation:def set_bit_32(n: int, i: int) -> int: """Set bit treating n as a 32-bit unsigned integer.""" if not 0 <= i < 32: raise ValueError(f"Position {i} out of range for 32-bit integer") result = n | (1 << i) return result & 0xFFFFFFFF # Mask to 32 bits # Sign bit demonstration (in 32-bit interpretation)n = 0n = set_bit_32(n, 31)print(f"After setting bit 31: {n} (hex: {hex(n)})")# 2147483648 (0x80000000) # Interpreting as signed 32-bit:def to_signed_32(n: int) -> int: """Convert 32-bit unsigned to signed interpretation.""" if n >= 0x80000000: return n - 0x100000000 return n print(f"As signed 32-bit: {to_signed_32(n)}")# -2147483648Setting bits is a core operation in many real systems. Let's explore practical applications.
Permission systems use bit setting to grant new capabilities to users or roles.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
// Role-based permission system using bits enum Permission { READ = 0, WRITE = 1, DELETE = 2, ADMIN = 3, AUDIT = 4, EXPORT = 5, IMPORT = 6, SHARE = 7,} // Permission constants (can compute or predefine)const PERM = { READ: 1 << Permission.READ, WRITE: 1 << Permission.WRITE, DELETE: 1 << Permission.DELETE, ADMIN: 1 << Permission.ADMIN, AUDIT: 1 << Permission.AUDIT, EXPORT: 1 << Permission.EXPORT, IMPORT: 1 << Permission.IMPORT, SHARE: 1 << Permission.SHARE,}; // Common role presetsconst VIEWER = PERM.READ;const EDITOR = PERM.READ | PERM.WRITE;const CONTRIBUTOR = PERM.READ | PERM.WRITE | PERM.SHARE;const ADMIN_ROLE = 0xFF; // All 8 permissions class User { constructor(public name: string, public permissions: number = 0) {} grantPermission(perm: number): void { this.permissions |= perm; // SET the permission bit } grantMultiple(...perms: number[]): void { for (const perm of perms) { this.permissions |= perm; } } hasPermission(perm: number): boolean { return (this.permissions & perm) === perm; } describePermissions(): string { const perms: string[] = []; for (const [name, bit] of Object.entries(PERM)) { if (this.permissions & bit) perms.push(name); } return perms.join(', ') || 'NONE'; }} // Usageconst alice = new User("Alice");console.log(`Alice starts with: ${alice.describePermissions()}`); alice.grantPermission(PERM.READ);console.log(`After READ grant: ${alice.describePermissions()}`); alice.grantMultiple(PERM.WRITE, PERM.SHARE);console.log(`After WRITE+SHARE: ${alice.describePermissions()}`); // Granting again (idempotent - no change)alice.grantPermission(PERM.READ);console.log(`After RE-granting READ: ${alice.describePermissions()}`); // Check permissionsconsole.log(`Can Alice WRITE? ${alice.hasPermission(PERM.WRITE)}`);console.log(`Can Alice DELETE? ${alice.hasPermission(PERM.DELETE)}`);Most languages provide a compound assignment operator |= that combines reading, ORing, and writing into a single expression:
n |= (1 << i); // Equivalent to: n = n | (1 << i)
This isn't just syntactic sugar—it has practical benefits:
Readability: The intention (modify in place) is immediately clear.
Atomicity (Sometimes): In some contexts (like Java volatile fields or certain C++ atomics), compound operators may have special memory ordering semantics.
Performance: While modern compilers optimize both forms identically, the compound form explicitly communicates the update pattern.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
// Compound assignment for bit setting // Long formlet flags1 = 0;flags1 = flags1 | (1 << 0);flags1 = flags1 | (1 << 2);flags1 = flags1 | (1 << 4);console.log(flags1.toString(2)); // 10101 = 21 // Compound assignment form (cleaner)let flags2 = 0;flags2 |= (1 << 0);flags2 |= (1 << 2);flags2 |= (1 << 4);console.log(flags2.toString(2)); // 10101 = 21 // Very compact chained form (less readable but sometimes seen)let flags3 = 0;flags3 |= (1 << 0) | (1 << 2) | (1 << 4);console.log(flags3.toString(2)); // 10101 = 21 // Building a bitmask incrementallyclass FlagBuilder { private value = 0; set(bit: number): this { this.value |= (1 << bit); return this; // Enable chaining } build(): number { return this.value; }} const flags4 = new FlagBuilder() .set(0) .set(2) .set(4) .build();console.log(flags4.toString(2)); // 10101 = 21 ---python# Compound assignment for bit setting # Long formflags1 = 0flags1 = flags1 | (1 << 0)flags1 = flags1 | (1 << 2)flags1 = flags1 | (1 << 4)print(bin(flags1)) # 0b10101 = 21 # Compound assignment form (cleaner)flags2 = 0flags2 |= (1 << 0)flags2 |= (1 << 2)flags2 |= (1 << 4)print(bin(flags2)) # 0b10101 = 21 # Combined single expressionflags3 = 0flags3 |= (1 << 0) | (1 << 2) | (1 << 4)print(bin(flags3)) # 0b10101 = 21 # Builder pattern with method chainingclass FlagBuilder: def __init__(self): self._value = 0 def set(self, bit: int) -> 'FlagBuilder': self._value |= (1 << bit) return self # Enable chaining def build(self) -> int: return self._value flags4 = (FlagBuilder() .set(0) .set(2) .set(4) .build())print(bin(flags4)) # 0b10101 = 21You've now mastered the bit-setting operation—the fundamental technique for turning bits on. Let's consolidate the key concepts.
n | (1 << i) sets bit i to 1 while preserving all other bits unchanged.n | mask | mask === n | mask.1 << i creates a mask with exactly one bit set at position i (value = 2^i).((1 << i) | (1 << j)), then OR once with n for efficiency.n |= mask for clear, in-place modification.| Operation | Formula | Example (n=5) |
|---|---|---|
| Set bit i | n | (1 << i) | 5 | (1<<1) = 7 |
| Set bits i,j | n | (1<<i) | (1<<j) | 5 | (1<<1) | (1<<3) = 15 |
| Set low k bits | n | ((1<<k) - 1) | 0 | ((1<<4) - 1) = 15 |
| Set bit (in place) | n |= (1 << i) | n |= (1<<1) → n=7 |
What's Next:
With checking and setting mastered, we now turn to the opposite operation: clearing a bit at position i—forcing a bit to 0 without affecting others. This is essential for revoking permissions, disabling features, and removing elements from bit-based sets.
You can now set any bit at any position to 1 with surgical precision. This operation forms the foundation for activating flags, granting permissions, and building bit-based data structures. Next, we'll learn the complementary operation of clearing bits.