#include <stdio.h>
#include <stdint.h>
#define EXTRACT_START_POS 4U
#define EXTRACT_END_POS 8U
#define POS_MASK(val) ((1 << (val + 1)) - 1)
// Define macros here
#define EXTRACT_DATA(val) (val & (POS_MASK(EXTRACT_END_POS - EXTRACT_START_POS) << EXTRACT_START_POS))
uint8_t extract_field(uint16_t reg)
{
uint8_t extracted_data = (uint8_t)((EXTRACT_DATA(reg)) >> EXTRACT_START_POS);
return extracted_data;
}
int main()
{
uint16_t reg;
scanf("%hx", ®);
printf("%u", extract_field(reg));
return 0;
}This program demonstrates a targeted Bit Field Extraction technique. It is designed to isolate and read a specific set of bits from a 16-bit register, a fundamental task in firmware development when parsing sensor data or hardware status flags.
The code is configured to "cut out" a specific window from a uint16_t (2-byte) value:
Start Position: Bit 4
End Position: Bit 8
Field Width: 5 bits (Bits 4, 5, 6, 7, and 8)
Value Range: Can represent any integer from 0 to 31 ($2^5 - 1$).
Step A: Creating a Relative Mask
The macro POS_MASK(EXTRACT_END_POS - EXTRACT_START_POS) calculates the width of the field. By subtracting the start from the end ($8 - 4 = 4$), it creates a 5-bit mask (binary 11111). This ensures the code only looks at a 5-bit wide window, regardless of where it is located in the register.
Step B: Alignment and Isolation (EXTRACT_DATA)
The 5-bit mask is shifted left by 4 positions (<< EXTRACT_START_POS) to align perfectly with the target bits in the register. A Bitwise AND (&) is then performed. This operation "blacks out" every bit in the register except for the data sitting in bits 4 through 8.
Step C: Normalization
The function extract_field takes the isolated bits and shifts them back to the right (>> EXTRACT_START_POS). This moves the data from its high-position "slot" down to the Least Significant Bit (LSB) position.
Example: If the raw bits at positions 4–8 represented the number 5, the shift converts the register value from 80 (binary ...01010000) to 5 (binary ...00000101).
Portability: By using EXTRACT_START_POS and EXTRACT_END_POS constants, the logic can be updated for different hardware registers by changing only two numbers.
Efficiency: The extraction happens using basic CPU instructions that execute in a single clock cycle, making it ideal for high-speed communication like SPI or CAN bus parsing.
Memory Safety: It returns a uint8_t, which is the smallest appropriate container for a 5-bit value, saving RAM in embedded systems.
Input
0x01F0
Expected Output
31