How do I extract specific 'n' bits of a 32-bit unsigned integer in C?
Asked Answered
C

10

49

Could anyone tell me as to how to extract 'n' specific bits from a 32-bit unsigned integer in C.

For example, say I want the first 17 bits of the 32-bit value; what is it that I should do?
I presume I am supposed to use the modulus operator and I tried it and was able to get the last 8 bits and last 16 bits as

unsigned last8bitsvalue=(32 bit integer) % 16
unsigned last16bitsvalue=(32 bit integer) % 32

Is this correct? Is there a better and more efficient way to do this?

Capacity answered 4/11, 2011 at 15:28 Comment(4)
Note that your code as written actually extracts the last 4 and 5 bits, respectively (not 8 and 16, as you wrote).Lecompte
@AaronDufour Can you please explain your comment. I am interested in why is that 4 and 5 bitsLeathery
@CholthiPaulTtiopic You can get the last n bits of a number x with x % (2 ^ n) (x % 16 -> x % 2^4 -> 4 bits, and similarly x % 32 -> 5 bits). If you do x % n then you'll find that your output only ranges from 0 to n-1, whereas n bits can contain numbers 0 to 2^n-1.Lecompte
@AaronDufour fantastic explanation!Leathery
S
33

If you want n bits specific then you could first create a bitmask and then AND it with your number to take the desired bits.

Simple function to create mask from bit a to bit b.

unsigned createMask(unsigned a, unsigned b)
{
   unsigned r = 0;
   for (unsigned i=a; i<=b; i++)
       r |= 1 << i;

   return r;
}

You should check that a<=b.

If you want bits 12 to 16 call the function and then simply & (logical AND) r with your number N

r = createMask(12,16);
unsigned result = r & N;

If you want you can shift the result. Hope this helps

Sphenogram answered 4/11, 2011 at 16:4 Comment(4)
no need to spend time looping for a small mask. just ((1 << n) - 1) << bTrite
@Sphenogram I think your function fails with an edge-case. If I want to get the first two bits, createMask gives me the 2nd and 3rd bit because it would do 1 << 1, followed by 1 << 2. The bit mask returned is 110 - which zeros out the first bit.Errol
@Errol if you want the first two bits then you have to call createMask with 0 and 1 as arguments, in order to get the 0x03 mask.Sphenogram
This is faster and worked for me as well with uint64_t's: ((1ull << (b - a)) - 1ull) << aThebault
S
90

Instead of thinking of it as 'extracting', I like to think of it as 'isolating'. Once the desired bits are isolated, you can do what you will with them.

To isolate any set of bits, apply an AND mask.

If you want the last X bits of a value, there is a simple trick that can be used.

unsigned mask = (1 << X) - 1;
lastXbits = value & mask;

If you want to isolate a run of X bits in the middle of 'value' starting at 'startBit'

unsigned mask = ((1 << X) - 1) << startBit;
isolatedXbits = value & mask;
Serbocroatian answered 4/11, 2011 at 15:58 Comment(6)
your emphasis on making Mask byte first is really helpful to solve such problemsNodal
need more explanation masking part. did not get muchOutput
@user765443: Suppose u wanna extract last 3 bits from 0101, 1 << 3 = 1000,1000-1=0111,0101 & 0111=101(last 3 bits extracted). (1<<X) -1 will always give u 0 as MSbit followed by all 1sLeaseback
This approach does not work, if X = 32 for int (or 64 for long)Hands
@Hands - You are correct; under the conditions you referenced, we run into undefined behaviour when bit-shifting. Thus, depending upon the processor, it might work (or not); in other words it is non-portable for those cases. The observation can also be made that if you are trying to extract or isolate all the bits, just access the variable as you would normally and don't bother applying any unnecessary masks.Serbocroatian
very well explained, clear, and concise. bravo!Hamill
S
33

If you want n bits specific then you could first create a bitmask and then AND it with your number to take the desired bits.

Simple function to create mask from bit a to bit b.

unsigned createMask(unsigned a, unsigned b)
{
   unsigned r = 0;
   for (unsigned i=a; i<=b; i++)
       r |= 1 << i;

   return r;
}

You should check that a<=b.

If you want bits 12 to 16 call the function and then simply & (logical AND) r with your number N

r = createMask(12,16);
unsigned result = r & N;

If you want you can shift the result. Hope this helps

Sphenogram answered 4/11, 2011 at 16:4 Comment(4)
no need to spend time looping for a small mask. just ((1 << n) - 1) << bTrite
@Sphenogram I think your function fails with an edge-case. If I want to get the first two bits, createMask gives me the 2nd and 3rd bit because it would do 1 << 1, followed by 1 << 2. The bit mask returned is 110 - which zeros out the first bit.Errol
@Errol if you want the first two bits then you have to call createMask with 0 and 1 as arguments, in order to get the 0x03 mask.Sphenogram
This is faster and worked for me as well with uint64_t's: ((1ull << (b - a)) - 1ull) << aThebault
F
10

Modulus works to get bottom bits (only), although I think value & 0x1ffff expresses "take the bottom 17 bits" more directly than value % 131072, and so is easier to understand as doing that.

The top 17 bits of a 32-bit unsigned value would be value & 0xffff8000 (if you want them still in their positions at the top), or value >> 15 if you want the top 17 bits of the value in the bottom 17 bits of the result.

Fourwheeler answered 4/11, 2011 at 15:31 Comment(2)
For the second part of your answer, you perhaps should have value >> 15 & 0x1ffff. The right-shift for integers is Implementation Defined; both GCC and MSVC have it arithmetic, not logical.Disharoon
@Joseph: question says that it's a 32bit unsigned integer, so the result of right shift is defined by the standard. If it were signed, the effect of right-shift on a negative value is (as you say) completely implementation-defined. It's not required to be either arithmetic or logical, the result could be anything. In practice of course everyone chooses an arithmetic shift for signed values, but if you're concerned about writing to the standard then it's better just to avoid it altogether (as the questioner has).Fourwheeler
S
10

There is a single BEXTR (Bit field extract (with register)) x86 instruction on Intel and AMD CPUs and UBFX on ARM. There are intrinsic functions such as _bextr_u32() (link requires sign-in) that allow to invoke this instruction explicitly.

They implement (source >> offset) & ((1 << n) - 1) C code: get n continuous bits from source starting at the offset bit. Here's a complete function definition that handles edge cases:

#include <limits.h>

unsigned getbits(unsigned value, unsigned offset, unsigned n)
{
  const unsigned max_n = CHAR_BIT * sizeof(unsigned);
  if (offset >= max_n)
    return 0; /* value is padded with infinite zeros on the left */
  value >>= offset; /* drop offset bits */
  if (n >= max_n)
    return value; /* all  bits requested */
  const unsigned mask = (1u << n) - 1; /* n '1's */
  return value & mask;
}

For example, to get 3 bits from 2273 (0b100011100001) starting at 5-th bit, call getbits(2273, 5, 3)—it extracts 7 (0b111).

For example, say I want the first 17 bits of the 32-bit value; what is it that I should do?

unsigned first_bits = value & ((1u << 17) - 1); // & 0x1ffff

Assuming CHAR_BIT * sizeof(unsigned) is 32 on your system.

I presume I am supposed to use the modulus operator and I tried it and was able to get the last 8 bits and last 16 bits

unsigned last8bitsvalue  = value & ((1u <<  8) - 1); // & 0xff
unsigned last16bitsvalue = value & ((1u << 16) - 1); // & 0xffff

If the offset is always zero as in all your examples in the question then you don't need the more general getbits(). There is a special cpu instruction BLSMSK that helps to compute the mask ((1 << n) - 1).

Spano answered 12/5, 2016 at 19:9 Comment(0)
B
9

This is a briefer variation of the accepted answer: the function below extracts the bits from-to inclusive by creating a bitmask. After applying an AND logic over the original number the result is shifted so the function returns just the extracted bits. Skipped index/integrity checks for clarity.

uint16_t extractInt(uint16_t orig16BitWord, unsigned from, unsigned to) 
{
  unsigned mask = ( (1<<(to-from+1))-1) << from;
  return (orig16BitWord & mask) >> from;
}
Boak answered 8/6, 2015 at 9:24 Comment(1)
This also seems to work with uint32_t input and return, instead of uint16_t.Esthete
D
8

If you need the X last bits of your integer, use a binary mask :

unsigned last8bitsvalue=(32 bit integer) & 0xFF
unsigned last16bitsvalue=(32 bit integer) & 0xFFFF
Downe answered 4/11, 2011 at 15:33 Comment(0)
S
4

Bitwise AND your integer with the mask having exactly those bits set that you want to extract. Then shift the result right to reposition the extracted bits if desired.

unsigned int lowest_17_bits = myuint32 & 0x1FFFF;
unsigned int highest_17_bits = (myuint32 & (0x1FFFF << (32 - 17))) >> (32 - 17);

Edit: The latter repositions the highest 17 bits as the lowest 17; this can be useful if you need to extract an integer from “within” a larger one. You can omit the right shift (>>) if this is not desired.

Scolex answered 4/11, 2011 at 15:32 Comment(0)
S
1
#define GENERAL__GET_BITS_FROM_U8(source,lsb,msb) \
    ((uint8_t)((source) & \
        ((uint8_t)(((uint8_t)(0xFF >> ((uint8_t)(7-((uint8_t)(msb) & 7))))) & \
             ((uint8_t)(0xFF << ((uint8_t)(lsb) & 7)))))))

#define GENERAL__GET_BITS_FROM_U16(source,lsb,msb) \
    ((uint16_t)((source) & \
        ((uint16_t)(((uint16_t)(0xFFFF >> ((uint8_t)(15-((uint8_t)(msb) & 15))))) & \
            ((uint16_t)(0xFFFF << ((uint8_t)(lsb) & 15)))))))

#define GENERAL__GET_BITS_FROM_U32(source,lsb,msb) \
    ((uint32_t)((source) & \
        ((uint32_t)(((uint32_t)(0xFFFFFFFF >> ((uint8_t)(31-((uint8_t)(msb) & 31))))) & \
            ((uint32_t)(0xFFFFFFFF << ((uint8_t)(lsb) & 31)))))))
Smithery answered 16/4, 2015 at 13:41 Comment(1)
Maybe not the most aesthetic way to do it but use define could be pretty interesting.Vestryman
S
0
int get_nbits(int num, int n)
{
return  (((1<<n)-1) & num);
}
Slander answered 7/3, 2021 at 15:26 Comment(2)
You should add some explanation as to how this code works (if, indeed, it does work).Epigynous
This doesn't even have the correct signature to work on unsigned int. You'll want to correct 1 to 1u, too.Collectanea
L
0

I have another method for accomplishing this. You can use a union of an integer type that has enough bits for your application and a bit field struct.

Example:

typedef thesebits
{

  unsigned long first4    : 4;
  unsigned long second4   : 4;
  unsigned long third8    : 8;
  unsigned long forth7    : 7;
  unsigned long fifth3    : 3;
  unsigned long sixth5    : 5;
  unsigned long last1     : 1;

} thesebits;

you can set that struct up to whatever bit pattern you want. If you have multiple bit patterns, you can even use that in your union as well.

typedef thesebitstwo
{

  unsigned long first8    : 8;
  unsigned long second8   : 8;
  unsigned long third8    : 8;
  unsigned long last8     : 8;

} thesebitstwo;

Now you can set up your union:

typedef union myunion 
{
   unsigned long mynumber;
   thesebits     mybits;
   thesebitstwo  mybitstwo;
} myunion;

Then you can access the bits you want from any number you assign to the member mynumber:

myunion getmybits;
getmybits.mynumber = 1234567890;

If you want the last 8 bits:

last16bits = getmybits.mybitstwo.last8;

If you want the second 4 bits:

second4bits = getmybits.mybits.second4;

I gave two examples kind of randomly assigned different bits to show. You can set the struct bit-fields up for whatever bits you want to get. I made all of the variables type unsigned long but you can use any variable type as long as the number of bits doesn't exceed those that can be used in the type. So most of these could have been just unsigned int and some even could be unsigned short

The caveat here is this works if you always want the same set of bits over and over. If there's a reason you may need to vary which bits you're looking at to anything, you could use a struct with an array that keeps a copy of the bits like so:

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>

typedef struct bits32
{

    bool b0              : 1;
    bool b1              : 1;
    bool b2              : 1;
    bool b3              : 1;
    bool b4              : 1;
    bool b5              : 1;
    bool b6              : 1;
    bool b7              : 1;
    bool b8              : 1;    
    bool b9              : 1;
    bool b10             : 1;
    bool b11             : 1;
    bool b12             : 1;    
    bool b13             : 1;
    bool b14             : 1;
    bool b15             : 1;
    bool b16             : 1;    
    bool b17             : 1;
    bool b18             : 1;
    bool b19             : 1;
    bool b20             : 1;    
    bool b21             : 1;
    bool b22             : 1;
    bool b23             : 1;
    bool b24             : 1;    
    bool b25             : 1;
    bool b26             : 1;
    bool b27             : 1;
    bool b28             : 1;    
    bool b29             : 1;
    bool b30             : 1;
    bool b31             : 1;

} bits32;

typedef struct flags32 {
    union 
    {
    
        uint32_t        number;
        struct bits32   bits;
    
    };
    bool                    b[32];
} flags32;

struct flags32 assignarray ( unsigned long thisnumber )
{
    struct flags32  f;
    f.number = thisnumber;
    
    f.b[0] = f.bits.b0;
    f.b[1] = f.bits.b1;
    f.b[2] = f.bits.b2;
    f.b[3] = f.bits.b3;
    f.b[4] = f.bits.b4;
    f.b[5] = f.bits.b5;
    f.b[6] = f.bits.b6;
    f.b[7] = f.bits.b7;
    f.b[8] = f.bits.b8;
    f.b[9] = f.bits.b9;
    f.b[10] = f.bits.b10;
    f.b[11] = f.bits.b11;
    f.b[12] = f.bits.b12;
    f.b[13] = f.bits.b13;
    f.b[14] = f.bits.b14;
    f.b[15] = f.bits.b15;
    f.b[16] = f.bits.b16;
    f.b[17] = f.bits.b17;
    f.b[18] = f.bits.b18;
    f.b[19] = f.bits.b19;
    f.b[20] = f.bits.b20;
    f.b[21] = f.bits.b21;
    f.b[22] = f.bits.b22;
    f.b[23] = f.bits.b23;
    f.b[24] = f.bits.b24;
    f.b[25] = f.bits.b25;
    f.b[26] = f.bits.b26;
    f.b[27] = f.bits.b27;
    f.b[28] = f.bits.b28;
    f.b[29] = f.bits.b29;
    f.b[30] = f.bits.b30;
    f.b[31] = f.bits.b31;

    return f;
    
}

int main ()

{

    struct flags32 bitmaster;
    bitmaster = assignarray(1234567890);

    printf("%d\n", bitmaster.number);
    printf("%d\n",bitmaster.bits.b9);
    printf("%d\n",bitmaster.b[9]);
    
    printf("%lu\n", sizeof(bitmaster));
    printf("%lu\n", sizeof(bitmaster.number));
    printf("%lu\n", sizeof(bitmaster.bits));
    printf("%lu\n", sizeof(bitmaster.b));
    
}

The issue with this last example is that it's not compact. The union itself is only 4 bytes, but since you can't do pointers to bit-fields (without complicated and debatably "non-standard" code), then the array makes a copy of each boolean value and uses a full byte for each one, instead of just the bit, so it takes up 9x the total memory space (if you run the printf statement examples I gave, you'll see).

But now, you can address each bit one-by-one and use a variable to index each one, which is great if you're not short on memory.

By using the typedefs above and the assignarray function as a constructor for flags32, you can easily expand to multiple variables. If you're OK just addressing with .b# and not being able to use a variable, you can just define the union as flags32 and omit the rest of the struct. Then you also don't need the assignarray function, and you'll use much less memory.

Linzy answered 17/5, 2022 at 22:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.