Search code examples
cbit-manipulation

How to bit manipulate a mask into a number


How can I change a range of bits in an unsigned byte (or bigger) without caring what are the current bits at those ranges.

0bXXXX'XXXX

I want to set bits at positions 2,3,4 to 0b101, so at the end the byte should become:

0bXXXX'101X

The mask for 2,3 and 4 bits I think will be 0b0000'1110 or 12

I tried:

unsigned char b = 255;
b = 0b101 &  ~( 12 << 1);

But this prints:

0000'0101

Solution

  • Clear bits: byte &= ~(0b111 << 2);
    Set bits to some data: byte |= 0b101 << 2;

    But note rule #1: no "magic numbers". Wth is 0b101 and why are we shifting it by 2? So start by defining named constants. If the bit-field we are dealing with is named "FOO", then for example:

    #define FOO_POS    2
    #define FOO_MASK   0x7u
    #define FOO       (FOO_MASK << FOO_POS)
    

    Complete example (C23):

    #include <stdio.h>
    
    #define FOO_POS    2
    #define FOO_MASK   0x7u
    #define FOO       (FOO_MASK << FOO_POS)
    
    int main(void) 
    {
      unsigned int bar = 0xFF;
      printf("%.2X %.8b\n", bar, bar);
    
      bar &= ~FOO;
      printf("%.2X %.8b\n", bar, bar);
    
      bar |= ((0b101 & FOO_MASK) << FOO_POS);
      printf("%.2X %.8b\n", bar, bar);
    }
    

    Just don't take such macros too far and start inventing some ugly setter/getter macro language for setting bits. C programmers are expected to know bitwise operations so there's no need to hide them behind ugly macros, as they are already the most clear when typed out explicitly.