How to extract specific bits from a number in C?

95,818

Solution 1

There are two building blocks that you need to know to build this yourself:

  • Getting N least significant bits requires constructing a bit mask with N ones at the end. You do it like this: ((1 << N)-1). 1 << N is 2 ^ N: it has a single 1 at the N+1st position, and all zeros after it. Subtracting one gives you the mask that you need.
  • Dropping M least significant bits is a simple shift to the right: k >> M

Now your algorithm for cutting out from M to N becomes a two-step process: you shift the original value M bits to the right, and then perform a bit-wise AND with the mask of N-M ones.

#define LAST(k,n) ((k) & ((1<<(n))-1))
#define MID(k,m,n) LAST((k)>>(m),((n)-(m)))

int main() {
    int a = 0xdeadbeef;
    printf("%x\n",  MID(a,4,16));
    return 0;
}

This fragment cuts out bits from 4, inclusive, to 16, exclusive, and prints bee when you run it. Bits are numbered from zero.

Solution 2

unsigned short extract(unsigned short value, int begin, int end)
{
    unsigned short mask = (1 << (end - begin)) - 1;
    return (value >> begin) & mask;
}

Note that [begin, end) is a half open interval.

Solution 3

It can be done like this:

mask = ~(~0 << (end - start + 1));
value = (n >> start) & mask;

where n is the original integer and value is the extracted bits.

The mask is constructed like this:

1. ~0 = 1111 1111 1111 1111 1111 1111 1111 1111
2. ~0 << (end - start + 1) = 1111 1111 1111 1111 1100 0000 0000 0000
   // assuming we are extracting 14 bits, the +1 is added for inclusive selection
   // ensure that end >= start
3. ~(~0 << (end - start + 1)) = 0000 0000 0000 0000 0011 1111 1111 1111

Now n is shifted right by start bits to align the desired bits to the left. Then a bitwise AND gives the result.

Solution 4

//To get value from specific position 'pos' to 'pos+offset' in number 'value'

#define bitGet(value, offset, pos) (((1ull << offset) - 1) & (value >> (pos - 1)))

//Set value 'newval' from position 'pos' to 'pos+offset' in number 'value'

#define bitSet(value, offset, pos, newval)  \
(~(((1ull << offset) - 1) << (pos - 1)) & value) | ((((1ull << offset) - 1) & newval) << (pos - 1))

Solution 5

Although its a very old question, I would like to add a different solution. Using macros,

/* Here, startBit : start bit position(count from LSB) endBit : end bit position(count from LSB) .NOTE: endBit>startBit number : the number from which to extract bits maxLength:the total bit size of number. */ `

#include <stdio.h>
#define getnbits(startBit,endBit,number,maxLength) \
  ( number &  ( (~0U >> (maxLength-endBit)) & (~0U << startBit) )  ) 

int main()
{
    unsigned int num=255;
    unsigned int start=1,end=5,size=sizeof(num)*8;

    printf("Inputs : %d %d %d %d \n ",start,end,num,size);
    printf("Input number : %d\n",num);

    if(end>start)
    {
        int result = getnbits(start,end,num,size-1);
        printf("Output : %u\n\n",result);
    }
    else
        printf("Error : EndBit is smaller than starBit!\n\n");

    return 0;
}

`

Output : Inputs : 1 5 255 32
Input number : 255
Output : 62

Here, 255 = 11111111 and 62 = 00111110

Share:
95,818
Usman
Author by

Usman

Updated on July 08, 2020

Comments

  • Usman
    Usman almost 4 years

    I need to extract specific part (no of bits) of a short data type in C.

    For Example I have a binary of 52504 as 11001101000 11000 and I want First 6 ( FROM LSB --> MSB i.e 011000 decimal 24) bits and rest of 10 bits ( 11001101000 decimal 820).

    Similarly I want this function to be too generalized to extract specific no of bits given "start" and "end" (i.e chunks of bits equivalent with some decimal value).

    I checked other posts, but those were not helpful, as given functions are not too much generalized.

    I need something that can work for short data type of C.

    Edit

    I am having the short array of size 2048 bytes. Where each Pixel is of 10 bits. So my 16 bit consisting each byte occupying some time 2 pixels data, sometimes 3 pixels data.

    Like

    ( PIXEL : 0,1 ) 10 BITS + 6 BITS

    then ( PIXEL : 1,2,3 ) 4 BITS ( 1st pixels remaining bits ) + 10 BITS + 2 BITS.

    and so on ..this pattern continues ... So, all I want to extract each pixel and make an entire array of having each pixels to be occupied wholy in on WHOLE BYTE ( of 16 bits ) like.. 1 byte should contain 1 DATA PIXEL, the other BYTE should contain other PIXEL value in whole 16 bits and so on so forth.

  • Usman
    Usman about 12 years
    returns wrong values.. For example..i have no 150 and its binary is 0000000010010110 ..I would need from start ( 2--5) bits..and they summs up with 22 . But this is not working at all.
  • Sufian Latif
    Sufian Latif about 12 years
    @Usman 22 is the rightmost 5 bits... did you do it correctly?
  • Usman
    Usman about 12 years
    yes of course either you pick First 5 bits or start from 2nd bit till 6th bit as i said earlier..it counts up to 22. So, I gave start = 1 and end = 5 or you can give it to end = 6...It MUST be 22. But its not returning 22, instead it returns 11 on start = 1 and end = 5.
  • Usman
    Usman about 12 years
    I don,t understand.. All I need specific parts of the binar bits.. I think I have edited the post to make it more clear..:-)
  • Sufian Latif
    Sufian Latif about 12 years
    @Usman But how come the bits 2 to 5 becomes 22? I don't understand that too. Bits 2 to 5 are 0101, right? 0000000010[0101]10 <- is the selection correct?
  • Usman
    Usman about 12 years
    Nops..I am considering the first bit as the most LSB rightest bit that is '0' and then the second bit is '1' , the third would be again '1' and 0. So.. in 10110..( I need 1011 that is starting in original sequence given above of 150, starts from 2nd bit to 5th bit).
  • Sufian Latif
    Sufian Latif about 12 years
  • Naren
    Naren over 3 years
    its giving wrong output, if i have 15 num and 1 to 2 bits (means 2nd and 3rd bit) i have to take out then it is giving 3 (0011) as answer, but the answer should come 6 (0110)