How to extract specific bits from a number in C?
Asked Answered
C

9

21

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.

Conqueror answered 10/4, 2012 at 14:5 Comment(5)
just mask what you want i.e. num & 0000000000111111 or if you want the other end (num & 1111111111000000) >> 6Frowsty
@hexa: you're probably right, but the question is a constructive question. What to do...? What to do...?Chavannes
Can you make the question a bit more specific please? First you say you want the two numbers from splitting into two parts, then you say you want to specify a start and an end, does this mean you want 3 numbers out? Top, middle, and bottom?Height
Actually i am processing the huge array of 2048 size of short carrying specific values of some pixels of an image taken from camera. Look at the editConqueror
C types don't guarantee the size. short may have 18 bits or 32 bits or any value that conforms to the C standard. You need to specify a specific size, or use sized ints such as uint8_t...Outfield
P
30

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.

Pacien answered 10/4, 2012 at 14:14 Comment(0)
E
18
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.

Evaporimeter answered 10/4, 2012 at 14:14 Comment(0)
M
12

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.

Margo answered 10/4, 2012 at 14:11 Comment(8)
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.Conqueror
@Conqueror 22 is the rightmost 5 bits... did you do it correctly?Margo
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.Conqueror
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..:-)Conqueror
@Conqueror 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?Margo
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).Conqueror
let us continue this discussion in chatMargo
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)Chalkboard
C
3
//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))
Cienfuegos answered 7/7, 2019 at 18:57 Comment(0)
P
2

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

Pupillary answered 2/5, 2017 at 9:29 Comment(0)
S
1
// This is the main project file for VC++ application project 
// generated using an Application Wizard.

#include "stdafx.h"

#using <mscorlib.dll>

using namespace System;


void fun2(int *parr)
{
    printf(" size of array is %d\n",sizeof(parr));
}
void fun1(void)
{
    int arr[100];
    printf(" size of array is %d\n",sizeof(arr));
    fun2(arr);
}

int extractBit(int byte, int pos) 
{
    if( !((pos >= 0) && (pos < 16)) )
    {
        return 0;
    }
    return ( ( byte & (1<<pos) ) >> pos);
}
int extractBitRange(int byte, int startingPos, int offset) 
{


   if(  !(((startingPos + offset) >= 0) && ( (startingPos + offset) < 16)) )
   {
        return 0;
   }
   return ( byte >> startingPos ) & ~(0xff << (offset + 1));
}

int _tmain()
{
    // TODO: Please replace the sample code below with your own.

    int value;
    signed int res,bit;
    signed int stPos, len;
    value = 0x1155;
    printf("%x\n",value);
    //Console::WriteLine("Hello World");
    //fun1();
    for(bit=15;bit>=0;bit--)
    {
        res =extractBit(value,bit);
        printf("%d",res);
    }
    stPos = 4;
    len = 5;
    res = extractBitRange(value, stPos, len);
    printf("\n%x",res);

    return 0;
}
Seamanlike answered 16/10, 2012 at 14:1 Comment(0)
S
0
void  f(short int last, short int first, short int myNr){
      //construct mask for last bits
      short int mask=0;
      for(int i=0;i<last;i++)
       { mask+=1;
        mask<<1;}
      short int aux= myNr;
      aux=aux&mask; // only last bits are left
      //construct mask for first bits
      mask=0;
      for(int i=0;i<first;i++)
       { mask+=0x8000h;
        mask>>1;} 
      aux=myNr;  
      aux&=mask;
      aux>>last; // only first bits are left and shifted
}

you can add parameters to get the values out or something

Sunbonnet answered 10/4, 2012 at 14:24 Comment(0)
M
0
unsigned int extract_n2mbits(unsigned int x, int n, int m)
{
unsigned int mask, tmp;
if (n < m) {
    n = n + m;
    m = n - m;
    n = n - m;
}
mask = 1 << (n - m + 1);
tmp = m;
while (tmp > 1) {
    mask = mask << 1 | 1 << (n - m + 1);
    tmp = tmp - 1;
}
return ((x & mask) >> (n - m + 1));
}
Mindful answered 6/2, 2013 at 21:30 Comment(0)
S
0

I know this is a very old question but obviously still relevent. Here is my contribution using the ((1 << N)-1) trick for getting the desrired bitmask. It wasn't asked here, but I'll offer up both ways to extract and store the desired bits. Let's say that someValue holds a 2-bit field called foo at bits 0-1 and a 3-bit field called bar at bits 3-5. Let's further assume you've got a code generator to hardcode the offsets into the setters and getters to simplify the interface because of course you do.

uint8_t someValue = 0;

inline uint8_t getFoo() const {
  //start bit = 0, size in bits = 2, end = 2
  uint8_t mask = (1 << (2 - 0)) - 1; //end-start-1
  return (someValue >> 0) & mask; //shift back by start
}

inline void setFoo(uint8_t foo) {
  someValue &= ~(((1 << (2 - 0)) - 1) << 0); //end-start-1, shift by start
  someValue |= foo << 0; //shift by start
}

inline uint8_t getBar() const {
  //start bit = 3, size in bits = 3, end = 6
  uint8_t mask = (1 << (6 - 3)) - 1; //end-start-1
  return (someValue >> 3) & mask; //shift back by start
}

inline void setBar(uint8_t bar) {
  someValue &= ~(((1 << (6 - 3)) - 1) << 3); //end-start-1, shift by start
  someValue |= bar << 3; //shift by start bit
}
Sausa answered 26/2 at 21:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.