Jo Jo
Jo Jo

Reputation: 67

Set first 10 bit of int

I have a 32-bit int and I want to set the first 10 bit to a specific number.

IE

The 32-bit int is:

11101010101010110101100100010010

I want the first 10 bit to be the number 123, which is

0001111011

So the result would be

00011110111010110101100100010010

Does anyone know the easiest way I would be able to do this? I know that we have to do bit-shifting but I'm not good at it so I'm not sure

Thank you!

Upvotes: 1

Views: 2975

Answers (5)

satur9nine
satur9nine

Reputation: 15042

How about using bit fields in C combined with a union? The following structure lets you set the whole 32-bit value, the top 10 bits or the bottom 22 bits. It isn't as versatile as a generic function but you can't easily make a mistake when using it. Be aware this and most solutions may not work on all integer sizes and look out for endianness as well.

union uu {
    struct {
        uint32_t bottom22 : 22;
        uint32_t top10 : 10;
    } bits;
    uint32_t value;
};

Here is an example usage:

int main(void) {
    union uu myuu;
    myuu.value = 999999999;
    printf("value = 0x%08x\n", myuu.value);

    myuu.bits.top10 = 0;
    printf("value = 0x%08x\n", myuu.value);

    myuu.bits.top10 = 0xfff;
    printf("value = 0x%08x\n", myuu.value);

    return 0;
}

The output is:

value = 0x3b9ac9ff
value = 0x001ac9ff
value = 0xffdac9ff

Upvotes: 0

David C. Rankin
David C. Rankin

Reputation: 84551

You can also take a mask and replace approach where you zero the lower bits required to hold 123 and then simply | (OR) the value with 123 to gain the final result. You can accomplish the exact same thing with shifts as shown by several other answers, or you can accomplish it with masks:

#include <stdio.h>

#ifndef BITS_PER_LONG
#define BITS_PER_LONG 64
#endif

#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif

char *binpad2 (unsigned long n, size_t sz);

int main (void) {


    unsigned x = 0b11101010101010110101100100010010;
    unsigned mask = 0xffffff00; /* mask to zero lower 8 bits  */
    unsigned y = 123;           /* value to replace zero bits */

    unsigned masked = x & mask; /* zero the lower bits        */

    /* show intermediate results */
    printf ("\n x      : %s\n", binpad2 (x, sizeof x * CHAR_BIT));
    printf ("\n & mask : %s\n", binpad2 (mask, sizeof mask * CHAR_BIT));
    printf ("\n masked : %s\n", binpad2 (masked, sizeof masked * CHAR_BIT));
    printf ("\n | 123  : %s\n", binpad2 (y, sizeof y * CHAR_BIT));

    masked |= y;    /* apply the final or with 123 */

    printf ("\n final  : %s\n", binpad2 (masked, sizeof masked * CHAR_BIT));


    return 0;
}

/** returns pointer to binary representation of 'n' zero padded to 'sz'.
 *  returns pointer to string contianing binary representation of
 *  unsigned 64-bit (or less ) value zero padded to 'sz' digits.
 */
char *binpad2 (unsigned long n, size_t sz)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;
    register size_t i;

    for (i = 0; i < sz; i++)
        *--p = (n>>i & 1) ? '1' : '0';

    return p;
}

Output

$ ./bin/bitsset

 x      : 11101010101010110101100100010010

 & mask : 11111111111111111111111100000000

 masked : 11101010101010110101100100000000

 | 123  : 00000000000000000000000001111011

 final  : 11101010101010110101100101111011

Upvotes: 0

chux
chux

Reputation: 153358

  1. Convert inputs to unsigned 32-bit integers

    uint32_t num = strtoul("11101010101010110101100100010010", 0, 2);
    uint32_t firstbits = 123;
    
  2. Mask off the lower 32-10 bits. Create mask by shifting a unsigned long 1 22 places left making 100_0000_0000_0000_0000_0000 then decrementing to 11_1111_1111_1111_1111_1111

    uint32_t mask = (1UL << (32-10)) - 1;
    num &= mask;
    
  3. Or in firstbits shifted left by 32-10

    num |= firstbits << (32-10);
    
  4. Or in 1 line:

    (num & (1UL << (32-10)) - 1) | (firstbits*1UL << (32-10))
    

Detail about firstbits*1UL. The type of firstbits is not defined by OP and may only be a 16-bit int. To insure code can shift and form an answer that exceeds 16 bits (the minimum width of int), multiple by 1UL to insure the value is unsigned and has at least 32 bit width.

Upvotes: 1

Scott Hunter
Scott Hunter

Reputation: 49803

You can "erase" bits (set them to 0) by using a bit wise and ('&'); bits that are 0 in either value will be 0 in the result.

You can set bits to 1 by using a bit wise or ('|'); bits that are 1 in either value will be 1 in the result.

So: and your number with a value where the first 10 bits are 0 and the rest are 1; then 'or' it with the first 10 bits you want put in, and 0 for the other bits. If you need to calculate that value, then a left-shift would be the way to go.

Upvotes: 0

user2371524
user2371524

Reputation:

uint32_t result = (input & 0x3fffff) | (newval << 22);

0x3fffff masks out the highest 10 bits (it has the lowest 22 bits set). You have to shift your new value for the highest 10 bits by 22 places.

Upvotes: 2

Related Questions