Extract a Bit Field from 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 extract_field(uint32_t reg, uint8_t pos, uint8_t len) 
{
    uint32_t extract_value = 0;
    extract_value = (reg & MASK(pos, len)) >> pos;
    return extract_value;
}

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

Solving Approach

This code provides a generic way to extract a bit-field (a specific sequence of bits) from a 32-bit register. It is essentially a more flexible version of the "nibble extractor" you saw earlier, as it allows you to define exactly where the field starts and how long it is.

1. The Macro: MASK(pos, len)

The heart of the program is the macro that generates a "window" of 1s.

  • 1ULL << (pos + len): This shifts a 1 to the left past the end of our desired field. We use 1ULL (Unsigned Long Long) to prevent overflow if the field extends to the 31st bit.

  • - 1: Subtracting 1 turns all bits below that position into 1s.

  • >> pos) << pos: Similar to the range-setter, this "chops off" the 1s below our starting position.

  • Example: For pos=2, len=3, the macro creates a mask where bits 2, 3, and 4 are 1 (00011100).

2. The Function: extract_field

This function uses the generated mask to pull the data out.

  1. Bitwise AND (reg & MASK): This "silences" every bit in the register except for the ones inside our window.

  2. Right Shift (>> pos): The isolated bits are still floating in the middle of the register. This shift moves them all the way to the right (starting at bit 0). This converts the "raw" bit pattern into a standard numerical value.

Step-by-Step Example

Imagine a 32-bit register representing a hardware status. Bits 4, 5, and 6 represent a "Sensor ID".

  • Input: reg = 114 (Binary: ...01110010), pos = 4, len = 3.

Step

Operation

Result (Binary)

Mask Generation

MASK(4, 3)

...01110000 (Hex: 0x70)

Isolation (AND)

114 & 0x70

...01110000

Alignment (Shift)

0x70 >> 4

...00000111

Final Result

Return 7

The Sensor ID is 7.

Key Takeaways for Others

  • Bit-Field Isolation: This is the standard way to read "sub-variables" packed into a single register, which is very common in automotive (CAN/UDS) and embedded systems.

  • Type Safety: Using uint32_t ensures the register is treated as 32 bits, and the 1ULL in the macro is a "safety first" practice to handle shifts that might otherwise exceed the size of a standard integer.

  • Efficiency: This approach uses only three CPU operations (Shift, Subtract, AND), making it significantly faster than using a struct with bit-fields in some compilers.

Upvote
Downvote
Loading...

Input

3060793344 28 4

Expected Output

11