Clear Specific Bits in a 32-bit Register

Code

#include <stdio.h>
#include <stdint.h>
#include <limits.h>

#define MASK(pos, len)   (((1ULL << (pos + len)) - 1) >> pos) << pos

uint32_t clear_bits(uint32_t reg, uint8_t pos, uint8_t len) 
{
    reg &= ~((uint32_t)MASK(pos, len));
    return reg;
}

int main() 
{
    uint32_t reg;
    uint8_t pos, len;
    scanf("%u %hhu %hhu", &reg, &pos, &len);
    printf("%u", clear_bits(reg, pos, len));
    return 0;
}

Solving Approach

This program is a professional-grade utility for clearing a specific range of bits within a 32-bit register. "Clearing" means forcing a selected group of bits to 0 while ensuring all other bits in the register remain exactly as they were.

1. The Masking Strategy

The code uses a Negative Mask (often called an "Inverse Mask") to target a specific "window" of bits.

  • MASK(pos, len): This generates a sequence of 1s exactly where you want to clear the bits. For example, if pos=2 and len=3, the mask is 000...011100 (binary).

  • ~ (Bitwise NOT): This operator flips every single bit in that mask.

    • The 1s (your target zone) become 0s.

    • The 0s (the protected zone) become 1s.

    • Result: 111...100011 (binary).

2. The Clearing Operation: reg &= ...

By using the Bitwise AND (&) with this inverted mask, the code achieves two things simultaneously:

  1. In the Target Zone: Anything ANDed with 0 results in 0. This effectively "wipes" those bits.

  2. In the Protected Zone: Anything ANDed with 1 stays the same (e.g., $1 \& 1 = 1$ and $0 \& 1 = 0$). This preserves the rest of the register.

Step-by-Step Example

Imagine you have a register controlling 8 LEDs. You want to turn off a group of 3 LEDs starting from position 2.

  • Input: reg = 255 (Binary: 11111111), pos = 2, len = 3.

Step

Operation

Binary Result

1. Create Mask

MASK(2, 3)

00011100

2. Invert Mask

~Mask

11100011

3. Apply AND

11111111 & 11100011

11100011

Final Result

Value: 227

Bits 2, 3, and 4 are now 0.

Key Technical Details

  • Safety with 1ULL: The macro uses 1ULL (Unsigned Long Long) during the shift. This is a critical safety feature; if you try to shift a standard 32-bit 1 by 32 positions, it causes "undefined behavior" in C. Using a 64-bit constant prevents this crash.

  • Explicit Casting: In the function, (uint32_t)MASK ensures the 64-bit macro result is correctly sized back down to 32 bits before the bitwise NOT operation, preventing unexpected behavior with high-order bits.

  • Efficiency: This is a constant-time $O(1)$ operation. It doesn't matter if you are clearing 1 bit or 31 bits; it happens in a single CPU cycle.

Upvote
Downvote
Loading...

Input

255 4 4

Expected Output

15