Search code examples
cbitset

Effectively set X-bits in a number N, starting from position P from MSB


The below code set X-bits in a number N starting position P from LSB (N is 32 bit Number)

//gcc 5.4.0
#include  <stdio.h>
unsigned int set_bits_pos(int N, int X, int P)
{
    unsigned int mask = ((1UL << X)-1) << P; 
    return (N|mask);
}

int main(void)
{
    unsigned int bits = 3, pos=5, num=0x0F;       
    printf("0x%X\n", set_bits_pos(num,bits,pos));
    return 0;
}

Output:

0xEF

How to convert the above function to set X-bits in number N, starting position P from MSB ? Best Possible way. Thanks

Edit: To Set from MSB and Arch Independent for both 32 & 64 bit N, after suggestions

//gcc 5.4.0
#include  <stdio.h>
size_t set_bits_pos(size_t N, int X, int P)
{
    size_t mask = ((1UL << X)-1) << ((8*sizeof(N)) - P - X); 
    return (N|mask);
}

int main(void)
{
    size_t num=0x0F;
    int bits = 3, pos=5;       
    printf("0x%X\n", set_bits_pos(num,bits,pos));
    return 0;
}

Output:

0x0700000F

Solution

  • I'd recommend using the exact-width integer types:

    #include <inttypes.h>
    
    uint32_t  set_low32(const uint32_t     value,
                        const unsigned int bits,
                        const unsigned int skip)
    {
        uint32_t  mask = (~(uint32_t)0) >> (32 - bits);
        return value | (mask << skip);
    }
    
    uint64_t  set_low64(const uint64_t     value,
                        const unsigned int bits,
                        const unsigned int skip)
    {
        uint64_t  mask = (~(uint64_t)0) >> (64 - bits);
        return value | (mask << skip);
    }
    
    uint32_t  set_high32(const uint32_t     value,
                         const unsigned int bits,
                         const unsigned int skip)
    {
        uint32_t  mask = (~(uint32_t)0) << (32 - bits);
        return value | (mask >> skip);
    }
    
    uint64_t  set_high64(const uint64_t     value,
                         const unsigned int bits,
                         const unsigned int skip)
    {
        uint64_t  mask = (~(uint64_t)0) << (64 - bits);
        return value | (mask >> skip);
    }
    

    bits is the number of bits to set (X in question), and skip is the number of low/high bits to skip (P in question).