hektor
hektor

Reputation: 1025

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

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?

Upvotes: 50

Views: 203395

Answers (10)

Sparky
Sparky

Reputation: 14117

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;

Upvotes: 93

Trashman
Trashman

Reputation: 1596

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.

Upvotes: 0

Karthik J
Karthik J

Reputation: 21

int get_nbits(int num, int n)
{
return  (((1<<n)-1) & num);
}

Upvotes: 1

jfs
jfs

Reputation: 414865

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).

Upvotes: 11

pnezis
pnezis

Reputation: 12331

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

Upvotes: 35

florind
florind

Reputation: 391

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;
}

Upvotes: 10

jeboo
jeboo

Reputation: 103

#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)))))))

Upvotes: 1

Arkku
Arkku

Reputation: 42159

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.

Upvotes: 4

C&#233;dric Julien
C&#233;dric Julien

Reputation: 80851

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

Upvotes: 7

Steve Jessop
Steve Jessop

Reputation: 279415

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.

Upvotes: 10

Related Questions