How to extract specific bits from a number in C?
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 withN
ones at the end. You do it like this:((1 << N)-1)
.1 << N
is2 ^ N
: it has a single1
at theN+1
st 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
Usman
Updated on July 08, 2020Comments
-
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 about 12 yearsreturns 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 about 12 years@Usman 22 is the rightmost 5 bits... did you do it correctly?
-
Usman about 12 yearsyes 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 about 12 yearsI 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 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 about 12 yearsNops..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 about 12 years
-
Naren over 3 yearsits 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)