简体   繁体   中英

How to return multiple bits from a number in C

I have a function to extract a single bit from a number:

int getBit (int value, int position) {

    return value & (1 << position));

    }

But how do I do it for a range (both for signed and unsigned numbers)? For instance:

get bits 10:14 from 0x12345678 (signed 0) = 0x15

int getField (int value, int hi, int lo, bool isSigned)

You just have to create a mask:

int createMask(int a, int b){
int c = a;
int mask = 0;
/*First we set the lenght of the mask*/
while(c <= b){  /*Including b*/
mask <<= 1;
mask = mask|1;
c++;
}
/*Then we set the position to the mask, the first bit is in the position 0*/
c=0;
while(c<a){
c++;
mask <<= 1 ;

}
return mask;
}

I haven't tested the function yet, but its just for explaining a way to make a mask.

And the final function may be something like this:

int getBits(int value, int a, int b){
int mask = createMask(a, b);
mask &= value;
//Now we have to move the bits to the right
while(a>0){
mask >>= 1;
a--;
}
return mask;

}

An example, if you want the first 6 bits, you have to code: getBits(myValue, 0, 5).

Im not sure what did you mean about the signeds and unsigneds numbers, but i hope it can help you.

Srry for my english.

I suspect you might want to approach the entire problem in a different way. Rather than extracting bits, why not just use bit masks.

For example, to check if the most significant bit in a byte is enabled:

if(byte & 0xf0) {}

To check for the least significant bit it would be:

if(byte & 0x01) {}

To check for multiple (or a "range") of bits, say the low order nibble:

if(byte & 0x0f) {}

From what you've said, I suspect this is much closer to what you want and much simpler than shifting to extract bits.

That was a bit of fun :) In three easy steps:

  1. shift your value right by the amount lo and decrease hi with lo . This simplifies the problem to 'get the lowest hi bits'.

  2. clip off the highest bits -- a custom mask is created on the fly.

  3. if necessary, use the highest bit to sign-extend the result (bitfiddling based on Sign extending from a constant bit width in C# ).

I don't know the reason for the suggested function prototype, but I would suggest using the order lo, hi rather than hi, lo . Somehow 10,14 feels more natural than the other way around, even though bits count down from high to low, when counted left to right -- the computer is supposed to make things easier for us!

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

int getField (int value, int hi, int lo, bool isSigned)
{
    /* step 1: clip off lower bits */
    value >>= lo;
    hi -= lo-1;
    /* step 2: clip off higher bits */
    value &= ~(-1<<hi);
    /* step 3: extend sign */
    if (isSigned && (value & (1<<(hi-1))))
        value |= -(1<<hi);
    return value;
}

int main (void)
{
    int i;
    i = getField (0x123456c8, 14,10, true);
    printf ("i = %d / %Xh\n", i,i);
    return 0;
}

Result:

i = -11 / FFFFFFF5h

which is the correct bit set:

  16   12    8    4    0 <- bit position
...4    5    6    7    8 <- value
0100 0101 0110 0111 1000 <- bitwise
      --- --             <- mask
      101 01             <- result
 ..111101 01             < sign extended result

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM