set the m-bit to n-bit [closed]

Suppose Bits are numbered from LSB to MSB:

BIT NUMBER    31                                     0
               ▼                                     ▼
number bits    0000 0000 0000 0000 0000 0000 0001 0101 
               ▲    ^           ^                    ▲ 
              MSB   |           |                   LSB
                    |           | 
                   n=27        m=17

LSB - Least Significant Bit (numbered 0)
MSB - Most  Significant Bit (numbered 31) 

In the figure above, I have shown how bits are numbered from LSB to MSB.
Notice the relative positions of n and m where n > m.


To set (all one) bits from n to m


To set-1 all bits from position m to n (where n > m) in a 32-bit number.
You need a 32-bit mask in which all bits are 1 from n to m and remaining bits are 0.

For example, to set all bits from m=17 to n=27 we need mask like:

BIT NUMBER    31   n=27        m=17                  0
               ▼    ▼           ▼                    ▼
mask =         0000 1111 1111 1110 0000 0000 0000 0000

And if we have any 32-bit number, by bitwise OR (|) with this number we can set-1 all bits from m to n. All other bits will be unchanged.

Remember OR works like:

x | 1 = 1   , and 
x | 0 = x 

where x value can be either 1 or 0.

So by doing:

 num32bit = num32bit | mask; 

we can set n to m bit 1 and remaining bits will be unchanged. For example, suppose, num32bit = 0011 1001 1000 0000 0111 1001 0010 1101,

then:

0011 1001 1000 0000 0111 1001 0010 1101   <--- num32bit
0000 1111 1111 1110 0000 0000 0000 0000   <--- mask     
----------------------------------------  ---------------Bitwise OR operation  
0011 1111 1111 1110 0111 1001 0010 1101   <--- new number  
---- ▲           ▲  -------------------
     |-----------|   this bits are from `num32bit`
      all bits are   
      1 here

This is what I mean by:

     num32bit = num32bit | mask; 

##How to make the mask?

To make a mask in which all bits are 1 from n to m and others are 0, we need three steps:

  1. Create mask_n: All bits on Right side from n=27 are one

     BIT NUMBER     31  n=27                              0
                    ▼    ▼                                ▼
     mask_27=       0000 1111 1111 1111 1111 1111 1111 1111
    

    In programming this can be created by right-shift (>>) 4 times.

    And, why 4?

     4 = 32 - n - 1  ==> 31 - 27 ==> 4
    

    Also note: the complement (~) of 0 has all bits one,
    and we need unsigned right shift in C.
    Understand the difference between signed and unsigned right shift

  2. Create mask_m: All bits on left side from m=17 are one.

     BIT NUMBER    31              m=17                  0
                   ▼                ▼                    ▼
     mask_17       1111 1111 1111 1110 0000 0000 0000 0000
    
  3. Create mask: Bitwise AND of above to: mask = mask_n & mask_m:

     mask =         0000 1111 1111 1110 0000 0000 0000 0000
                         ▲           ▲
     BIT NUMBER          27          17
    

And, below is my getMask(n, m) function that returns a unsigned number that looks like mask in step-3.

#define BYTE 8
typedef char byte; // Bit_sizeof(char) == BYTE
unsigned getMask(unsigned n,
              unsigned m){
    byte noOfBits = sizeof(unsigned) * BYTE;
    unsigned mask_n = ((unsigned)~0u) >> (noOfBits - n - 1),
             mask_m = (~0u) << (noOfBits - m),
             mask = mask_n & mask_m; // bitwise & of 2 sub masks
    return mask;
}

To test my getMask() I have also written a main() function and a binary() function, which prints a given number in binary format.

void binary(unsigned);
int main(){
    unsigned num32bit = 964720941u;
    unsigned mask = 0u;
    unsigned rsult32bit;
    int i = 51;     
    mask = getMask(27, 17);
    rsult32bit  = num32bit | mask;  //set n to m bits 1
    printf("\nSize of int is = %ld bits, and " 
           "Size of unsigned = %ld e.g.\n", sizeof(int) * BYTE,
                                            sizeof(unsigned) * BYTE);
    printf("dec= %-4u, bin= ", 21);
    binary(21);
    printf("\n\n%s %d\n\t   ", "num32bit =", num32bit); 
    binary(num32bit);
    printf("mask\t   "); 
    binary(mask);
    while(i--) printf("-");
    printf("\n\t   "); 
    binary(rsult32bit);
    printf("\n");
    return EXIT_SUCCESS;
}
void binary(unsigned dec){
  int i = 0,
      left = sizeof(unsigned) * BYTE - 1;
  for(i = 0; left >= 0; left--, i++){
    printf("%d", !!(dec & ( 1 << left )));
    if(!((i + 1) % 4)) printf(" ");
  }
  printf("\n");
}  

This test code runs like (the output is quite same as I explained in above example):

Output of code: 
-----------------
$ gcc b.c 
:~$ ./a.out 

Size of int is = 32 bits, and Size of unsigned = 32 e.g.
dec= 21  , bin= 0000 0000 0000 0000 0000 0000 0001 0101 

num32bit = 964720941
           0011 1001 1000 0000 0111 1001 0010 1101 
mask       0000 1111 1111 1110 0000 0000 0000 0000 
---------------------------------------------------
           0011 1111 1111 1110 0111 1001 0010 1101 
:~$ 

Additionally, you can write getMask() function in shorter form in two statements, as follows:

unsigned getMask(unsigned n,
                 unsigned m){
    byte noOfBits = sizeof(unsigned) * BYTE;
    return ((unsigned)~0u >> (noOfBits - n - 1)) &
           (~0u << (noOfBits -m));
}           

Note: I removed redundant parentheses, to clean up the code. Although you never need to remember precedence of operators, as you can override precedence using (), a good programmer always refers to precedence table to write neat code.

A better approach may be to write a macro as below:

#define _NO_OF_BITS sizeof(unsigned) * CHAR_BIT
#define MASK(n, m)  (((unsigned)~0u >> (_NO_OF_BITS - n - 1)) & \
                    (~0u << (_NO_OF_BITS - m)))

And call like:

result32bit  = num32bit | MASK(27, 17);

To reset (all zero) bits from n to m


To reset all bits from n to m = 0, and leave the rest unchanged, you just need complement (~) of mask.

mask      0000 1111 1111 1111 1000 0000 0000 0000 
~mask     1111 0000 0000 0000 0111 1111 1111 1111   <-- complement 

Also instead of | operator to set zero & is required.

remember AND works like:

x & 0 = 0   , and 
x & 0 = 0 

where x value can be 1 or 0.

Because we already have a bitwise complement ~ operator and and & operator, we just need to do:

rsult32bit  = num32bit & ~MASK(27, 17);

And it will work like:

num32bit = 964720941
       0011 1001 1000 0000 0111 1001 0010 1101 
mask   1111 0000 0000 0000 0111 1111 1111 1111 
---------------------------------------------------
       0011 0000 0000 0000 0111 1001 0010 1101 

Leave a Comment