Mask and extract bits in C - c

I've been looking at posts about masks, but I still can't get my head around how to extract certain bits from a number in C.
Say if we have an integer number, 0001 1010 0100 1011, its hexadecimal representation is 0x1A4B, right? If I want to know the 5th to 7th number, which is 101 in this case, shall I use int mask= 0x0000 1110 0000 0000, int extract = mask&number?
Also, how can I check if it is 101? I guess == won't work here...

Masking is done by setting all the bits except the one(s) you want to 0. So let's say you have a 8 bit variable and you want to check if the 5th bit from the is a 1. Let's say your variable is 00101100. To mask all the other bits we set all the bits except the 5th one to 0 using the & operator:
00101100 & 00010000
Now what this does is for every bit except the 5th one, the bit from the byte on the right will be 0, so the result of the & operation will be 0. For the 5th bit, however, the value from the right bit is a 1, so the result will be whatever the value of hte 5th bit from the left byte is - in this case 0:
Now to check this value you have to compare it with something. To do this, simply compare the result with the byte on the right:
result = (00101100 & 00010000) == 00000000
To generalize this, you can retrieve any bit from the lefthand byte simply by left-shifting 00000001 until you get the bit you want. The following function achieves this:
int getBit(char byte, int bitNum)
{
return (byte & (0x1 << (bitNum - 1)))
}
This works on vars of any size, whether it's 8, 16, 32 or 64 (or anything else for that matter).

Assuming the GCC extension 0b to define binary literals:
int number = 0b0001101001001011; /* 0x1A4B */
int mask = 0b0000111000000000; /* 0x0E00 */
/* &'ed: 0b0000101000000000; 0x0A00 */
int extract = mask & number; /* 0x0A00 */
if (extract == 0b0000101000000000)
/* Or if 0b is not available:
if (extract == 0x0a00 ) */
{
/* Success */
}
else
{
/* Failure */
}

You need to mask and shift. Either shift the value you are comparing to, or the value you are comparing. I find it easier to think about by shifting the value you are comparing to. So if you're trying to extract the 5th to 7th digits (from the left), you shift right 9 positions (16-7) so that the 7th digit is now the rightmost, then apply 0x7 (111 in binary) as a mask to get only the rightmost three binary digits
int i = 0x1A4B;
if (((i >> 9) & 0x07) == 0x05) { // 0x05 = 101 in binary
//do what you need to
}

First, the digits in binary are (usually) counted from the right (10th and 12th digit) or you say 5th and 7th most significant digits.
int mask = 0x0E00; // 0000 1110 0000 0000;
int extract = mask & number;
results in:
extract = 0000 1010 0000 0000
You can do
if (extract == 0x0A00 /*0000 1010 0000 0000*/){}
to test, or:
if (( extract >> 9 ) == 0x05){}
Both of the statements in the if will return true with your sample number.
Usually with a mask you will find yourself testing a single digit. You could use a function like this to test it:
bool digit_value( unsigned int number, unsigned int digit)
{
return (1 << digit) & number;
}
int main()
{
unsigned int number = 0x1A4B;
int should_be_three = 0;
should_be_three += digit_value(number, 10);
should_be_three += !digit_value(number, 11);
should_be_three += digit_value(number, 12);
printf("%s", (should_be_three == 3?"it worked":"it didn't work"));
return 0;
}

It may be simpler to check bits one-by-one, not all at once.
At first, you create mask for interested bit:
int fifthBitMask = 1 << 4;
int fifthBitResult = number & fifthBitMask;
int seventhBitMask = 1 << 6;
int seventhBitResult = number & seventhBitMask;
Now, you can compare results with zero OR with mask.
Comparing with zero can be omitted, so you can just use simple if:
if (fifthBitResult && seventhBitResult)
{
//your code here
}
Also, you can compare with masks. After operation &, in result will set only bits, which was set in mask.
So, it could like this:
if (fifthBitResult == fifthBitMask && seventhBitResult == seventhBitMask)
{
// your code here
}
So, if result of operation is equals to mask, you can do this with one operation:
int mask = 0x5 << 4; // 0x5 is hex representation of 101b
int result = number & mask;
if (result == mask)
{
// your code here
}

shall I use int mask= 0x0000 1110 0000 0000, int extract = mask&number?-
Yes, you can do this.
Also, how can I check if it is 101?
Sure you can check this-
0000 1010 0000 0000 which is 1280 in int.
extract== 1280

First of all, your calculation for bits 7-6-5 is incorrect. You stated it was 101, but it is 010 (for x1a43).
Second of all, to get these bits (the value represented by these bits) you should do &0xE0.
int my_bits_from_5to7 = number & 0xE0;

Related

Bitwise operations and masks: return bit values of the original variable that are set in the mask

It's my first time wondering here when the same question wasn't asked previously, therefore I have to ask it myself:)
There is a device (won't go in depth with that, since it's irrelevant for now) that I am working with where I have two inputs, which have length of 16 bits each. The 1st one of the inputs has the later needed values, and the 2nd one has the "locations" from where we want to find the values of 1st one's inputs. Let me show an example:
EDIT: clarification: the mask can be anything that's 16-bits in length and 8 bits set. Not just having the lowest two nibbles set (1), it's only so simple to just illustrate the scenario.
input: 0101 1011 0000 0111
mask: 0011 0011 0011 0011
output: 0001 0011 0000 0011
When mask is set at 1, the machine needs to return the input's value whether its 1 or 0, doesn't matter. The device uses the value regardless of that later on.
I can find solutions for this with simple &, as above, but it ain't enough since my hardware has its limitations and there are resources to be saved. As the example shows, the mask may have only contain at max 8 bits set since some things on the circuit board are mutually exclusive and I want to and can have my output to be only 8 bits in length:
output: xx01 xx11 xx00 xx11
saved to a variable as: 0111 0011
...I just don't know how, yet.
So how should I proceed, should I build on array where I save the locations of mask's set bits and then check value form the input, or is there a more efficient way to to this. Regarding scanning values etc. doesn't matter since I can handle that, at the moment we can treat the input and the mask just as any 16-bit long integers for example. In the short bit of code I used the same mock decimal values as I used in the binary examples earlier.
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t input=23303; //1st input, gives the 1s and 0s to be extracted
uint16_t mask=13107; //2nd input, defines the locations of needed 1s and 0s
uint8_t fi; //Filtered inputs=input after masking, this one to be returned
/*something needs to be done here*/
return fi; //With these inputs, this should be 115
return 0;
}
the mask can be anything that's 16-bits in length and 8 bits set. ...
Iterate through the result of input & mask and in every iteration check the mask bit set or not. If its set than set the corresponding bit in 8 bit result.
You can do:
#include <stdio.h>
#include <inttypes.h>
int main (void) {
uint16_t input = 23303;
uint16_t mask = 13107;
uint8_t fi = 0;
uint16_t res = input & mask;
for (unsigned int x = 0, c = 0; res; res >>= 1, ++x) {
if ((mask >> x) & 0x1) {
if (res & 0x1) {
fi |= 0x1 << c;
}
c++;
}
}
printf ("fi : %" PRIu8 "\n", fi);
return 0;
}
Output:
% ./a.out
fi : 115
Try out above solution with other mask values which are 16 bits in length and 8 bits set.
The most easiest way:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t input=23303; //1st input, gives the 1s and 0s to be extracted
uint16_t mask=13107; //2nd input, defines the locations of needed 1s and 0s
uint8_t fi; //Filtered inputs=input after masking, this one to be returned
/*something needs to be done here*/
uint16_t temp = input & mask;
uint8_t np0, np1, np2, np3;
np0 = temp &0x03;
np1 = (temp >> 4) & 0x03;
np2 = (temp >> 8) & 0x03;
np3 = (temp >> 12) & 0x03;
fi = np0 | (np1 << 2) | (np2 << 4) | (np3 << 6);
return fi; //With these inputs, this should be 115
return 0;
}
A little bit complex but may faster:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t input=23303; //1st input, gives the 1s and 0s to be extracted
uint16_t mask=13107; //2nd input, defines the locations of needed 1s and 0s
uint8_t fi; //Filtered inputs=input after masking, this one to be returned
/*something needs to be done here*/
fi = (temp &0x03) | ((temp >> 2) & 0x0C) | ((temp >> 4) & 0x30) | ((temp >> 6) & 0xC0);
return fi; //With these inputs, this should be 115
return 0;
}

Bitwise Arithmetic in C: Checking if a number is positive

x is an int,
I should be able to get the correct result when 0 is not involved. In attempts to account for the 0 case, I added "& x", which I believe now should return that a number is positive iff x > 0 and x is not 0 (because in c, any number other than 0 evaluates to true, correct?)
But, when running my tests, it says it has failed to evaulate 0x7fffffff as positive and I am not sure why!
Here is my code:
int mask = 0x1;
x = x >> 31;
int lsb = mask & x;
return ( (lsb) ^ 0x1) & (x) )
Edit: I have solved the problem by changing the code to the one below! Feedback is still very much appreciated, or any problems you may spot.
int mask = 0x1;
int lsb = (x >> 31) & mask;
int result = !(lsb ^ 0x1);
return !(result | !x);
If you know the representation is 2's complement, then you can do:
#include <stdio.h>
#define IS_NEG(a) (!!((1 << 31) & (a)))
int main(void)
{
int n;
while(1) {
scanf("%d", &n);
printf("negative: %d\n", IS_NEG(n));
}
return 0;
}
Explanation:
(1 << 31) will take the number 1 and shift it 31 times to the left, thus giving you 1000 0000 0000 0000 0000 0000 0000 0000. If you don't want to use the shift, you could use 0x80000000 too.
& (a) does a bitwise test with that big binary number. Since an AND operation only returns TRUE when both operands are TRUE, it follows that only if your number is negative (in 2's complement representation) that this will return TRUE.
!!(...) This double negation accounts for the fact that when you do that bitwise AND, the returned value by the expression will be (1 << 31) if the number is really negative. So we invert it (giving us zero), than invert it again (giving us 1). Therefore, this ensures that we get a ZERO or a ONE as a final result.
IS_NEG will return 0 on positive numbers AND 0, and returns 1 on all negative numbers.
Since the MSB will be a one when the number is negative, just test that bit. Note that this will only work for 32 bit integers (so you have to check that with a sizeof(int). The example returns 1 if a number is negative, but should be no problem reworking it to return 1 for positive numbers.
Let me know if this doesn't solve the problem. As I understand, you just want to test if any given int is positive/negative.
Edit: From the comments, I made a program to help you see what's going on.
#include <stdio.h>
#define IS_NEG(a) (!!(0x80000000 & (a)))
char buf[65];
/* converts an integer #n to binary represention of #bits bits */
char *bin(int n, unsigned int bits)
{
char *s = buf;
for(bits = (1 << (bits - 1)); bits > 0; bits = bits >> 1)
/* look! double negation again! Why this? :) */
*s++ = !!(n & bits) + 48;
*s = 0;
return buf;
}
int main(void)
{
/* R will be our partial result through-out the loop */
int r, n;
while(1) {
/* get the number */
scanf("%d", &n);
/* this is the inner part of the macro
* after this, we could say IS_NEG "becomes"
* (!!(r))
*/
r = n & 0x80000000;
printf("n & 0x80000000: 0x%x\n", r);
printf(" n = %s\n", bin(n, 32));
printf(" r = %s\n", bin(r, 32));
/* now we print what R is, so you see that the bitwise AND will
* return 0x80000000 on negative numbers. It will also print
* the NEGATION of R...
*
* After the printf(), we just assign the negated value to R.
*/
printf("r = 0x%x, !r = 0x%x\n", r, !r);
r = !r;
printf(" r = %s\n", bin(r, 32));
/* After this, IS_NEG "becomes" (!(r)) */
/* In the MACRO, this would be the second negation. */
printf("r = 0x%x, !r = 0x%x\n", r, !r);
r = !r;
printf(" r = %s\n", bin(r, 32));
/* Now, if R is 0, it means the number is either ZERO or
* POSITIVE.
*
* If R is 1, then the number is negative
*/
}
return 0;
}
https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign
Technically, an int could be a different size on different machines; use of an C99 int32_t from inttypes.h may help with portability. It might not even be encoded in the format you expect, Are there any non-twos-complement implementations of C?.
The really portable easy way, is of course,
static int is_positive(const int a) {
return a > 0;
}
The compiler will probably do a better job optimising it.
Edit: From comments, I came up with this; I tried to make it agnostic of the int-size. It is very much the same style as your own, checking whether the number is negative or zero, and inverting.
#include <stdio.h> /* printf */
#include <limits.h> /* INT_ */
#include <assert.h> /* assert */
/** Assumes a is a 2's-compliment number
and ~INT_MAX = 0b100..00, (checks if negative.) */
static int is_positive(const int a) {
unsigned b = a;
return !((b & ~INT_MAX) | !b);
}
static int is_really_positive(const int a) {
return a > 0;
}
static void test(const int a) {
printf("Number %d. Is positive %d.\n", a, is_positive(a));
assert(is_positive(a) == is_really_positive(a));
}
int main(void) {
test(INT_MIN);
test(-2);
test(-1);
test(0);
test(1);
test(2);
test(INT_MAX);
return 0;
}
Also related, https://stackoverflow.com/a/3532331/2472827.
Given the allowed operators from your comment, ! ~ & ^ | + << >>, edit: with the later constraint of no casts only the second alternative fits:
static int is_positive(unsigned x)
{
return ~x+1 >> (CHAR_BIT*sizeof x-1);
}
Here's the deal: conversion to unsigned is very carefully specified in C: if the signed value is unrepresentable in the unsigned type, one plus the maximum value representable in the unsigned type is added (or subtracted, no idea what prompted them to include this possibility) to the incoming value until the result is representable.
So the result depends only on the incoming value, not its representation. -1 is converted to UINT_MAX, no matter what. This is correct, since the universe itself runs on twos-complement notation . That it also makes the conversion a simple no-op reinterpretation on most CPUs is just a bonus.
You can get a 32-bit wide zero-or-nonzero test using bitwise or and shifts as follows:
int t;
t = x | (x>>16);
t = t | (t >> 8);
t = t | (t >> 4);
t = t | (t >> 2)
t = (t | (t>>1)) & 1;
This sets t to the "OR" of the low 32 bits of x and will 0 if and only if the low 32 bits are all zero. If the int type is 32 bits or less, this will be equivalent to (x != 0). You can combine that with your sign bit test:
return t & (~x >> 31);
To check whether given number is positive or negative. As you mentioned x is an int & I assume its 32-bit long signed int. for e.g
int x = 0x7fffffff;
How above x represented in binary
x => 0111 1111 | 1111 1111 | 1111 1111 | 1111 1111
| |
MSB LSB
Now to check given number is positive or negative using bitwise opaertor, just find out the status of last(MSB or 31st(longint) or 15th(short int)) bit status whether it's 0 or 1, if last bit is found as 0 means given number is positive otherwise negative.
Now How to check last bit(31st) status ? Shift last(31st) bit to 0th bit and perform bitwise AND & operation with 1.
x => 0111 1111 | 1111 1111 | 1111 1111 | 1111 1111
x>>31 => 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000
---------------------------------------------
&
1 => 0000 0000 | 0000 0000 | 0000 0000 | 0000 0001
---------------------------------------------
0000 0000 | 0000 0000 | 0000 0000 | 0000 0000 => its binary of zero( 0 ) so its a positive number
Now how to program above
static inline int sign_bit_check(int x) {
return (x>>31) & 1;
}
And call the sign_bit_check() like
int main(void) {
int x = 0x7fffffff;
int ret = sign_bit_check(x);
if(ret) {
printf("Negative\n");
}
else {
printf("positive \n");
}
return 0;
}

MSB (1-bit most left) index in C

How can I get the most significative 1-bit index from an unsigned integer (uint16_t)?
Example:
uint16_t x = // 0000 0000 1111 0000 = 240
printf("ffs=%d", __builtin_ffs(allowed)); // ffs=4
There is a function (__builtin_ffs) that return the least significative 1-bit (LSB) from a unsigned integer.
I want something opposite, I want some function which returns 8 applied to above example.
Remark: I have tried building my own function but I have found some problems with datatype size, which depends by compiler.
From the GCC manual at http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Other-Builtins.html:
Built-in Function: int __builtin_clz (unsigned int x)
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
So, highest set bit:
#define ONE_BASED_INDEX_OF_HIGHEST_SET_BIT(x) \
(CHAR_BIT * sizeof 1 - __builtin_clz(x)) // 1-based index!!
beware of x == 0 or x<0 && sizeof(x)<sizeof 0 though.
if I am reading this right (am I? I'm a little rusty on this stuff) you can do this as follows:
int msb = 0;
while(x) { // while there are still bits
x >>= 1; // right-shift the argument
msb++; // each time we right shift the argument, increment msb
}

How do I extract bits from 32 bit number

I have do not have much knowledge of C and I'm stuck with a problem since one of my colleague is on leave.
I have a 32 bit number and i have to extract bits from it. I did go through a few threads but I'm still not clear how to do so. I would be highly obliged if someone can help me.
Here is an example of what I need to do:
Assume hex number = 0xD7448EAB.
In binary = 1101 0111 0100 0100 1000 1110 1010 1011.
I need to extract the 16 bits, and output that value. I want bits 10 through 25.
The lower 10 bits (Decimal) are ignored. i.e., 10 1010 1011 are ignored.
And the upper 6 bits (Overflow) are ignored. i.e. 1101 01 are ignored.
The remaining 16 bits of data needs to be the output which is 11 0100 0100 1000 11 (numbers in italics are needed as the output).
This was an example but I will keep getting different hex numbers all the time and I need to extract the same bits as I explained.
How do I solve this?
Thank you.
For this example you would output 1101 0001 0010 0011, which is 0xD123, or 53,539 decimal.
You need masks to get the bits you want. Masks are numbers that you can use to sift through bits in the manner you want (keep bits, delete/clear bits, modify numbers etc). What you need to know are the AND, OR, XOR, NOT, and shifting operations. For what you need, you'll only need a couple.
You know shifting: x << y moves bits from x *y positions to the left*.
How to get x bits set to 1 in order: (1 << x) - 1
How to get x bits set to 1, in order, starting from y to y + x: ((1 << x) -1) << y
The above is your mask for the bits you need. So for example if you want 16 bits of 0xD7448EAB, from 10 to 25, you'll need the above, for x = 16 and y = 10.
And now to get the bits you want, just AND your number 0xD7448EAB with the mask above and you'll get the masked 0xD7448EAB with only the bits you want. Later, if you want to go through each one, you'll need to shift your result by 10 to the right and process each bit at a time (at position 0).
The answer may be a bit longer, but it's better design than just hard coding with 0xff or whatever.
OK, here's how I wrote it:
#include <stdint.h>
#include <stdio.h>
main() {
uint32_t in = 0xd7448eab;
uint16_t out = 0;
out = in >> 10; // Shift right 10 bits
out &= 0xffff; // Only lower 16 bits
printf("%x\n",out);
}
The in >> 10 shifts the number right 10 bits; the & 0xffff discards all bits except the lower 16 bits.
I want bits 10 through 25.
You can do this:
unsigned int number = 0xD7448EAB;
unsigned int value = (number & 0x3FFFC00) >> 10;
Or this:
unsigned int number = 0xD7448EAB;
unsigned int value = (number >> 10) & 0xFFFF;
I combined the top 2 answers above to write a C program that extracts the bits for any range of bits (not just 10 through 25) of a 32-bit unsigned int. The way the function works is that it returns bits lo to hi (inclusive) of num.
#include <stdio.h>
#include <stdint.h>
unsigned extract(unsigned num, unsigned hi, unsigned lo) {
uint32_t range = (hi - lo + 1); //number of bits to be extracted
//shifting a number by the number of bits it has produces inconsistent
//results across machines so we need a special case for extract(num, 31, 0)
if(range == 32)
return num;
uint32_t result = 0;
//following the rule above, ((1 << x) - 1) << y) makes the mask:
uint32_t mask = ((1 << range) -1) << lo;
//AND num and mask to get only the bits in our range
result = num & mask;
result = result >> lo; //gets rid of trailing 0s
return result;
}
int main() {
unsigned int num = 0xd7448eab;
printf("0x%x\n", extract(num, 10, 25));
}

C: bit operations on a variable-length bit string

I'm doing some bit operations on a variable-length bit string.
I defined a function setBits(char *res, int x, int y) that should work on that bit string passed by the *res variable, given a x and y (just to mention, I'm trying to implement something like a Bloom filter using 8 bits per x):
void setBits(char *res, int x, int y)
{
*res |= x << (y * 8)
}
E.g. given the following x-y-vectors {0,0} ; {0,1} ; {1,2} ; {2,3}, I expect a bit string like this (or vice-versa depending whether little- or big-endian, but that isn't important right now):
0000 0010 0000 0001 0000 0000 0000 0000
So the lowest 8 bits should come from {0,0}, the second 8 bits from {0,1}, the next 8 bits come from {1,2} and the last from {2,3}.
Unfortunately, and I don't seem to get the reason for that, setBits always returns only the last result (in this case i.e. the bit string from {2,3}). I debugged the code and realized that *res is always 0 - but why? What am I doing wrong? Is it that I chose char* that it doesn't work or am I completely missing something very stupid?
Assuming 8-bit chars, the maximum value you can store in *res is 0xff i.e. (1<<8)-1.
Consider what happens when you call setBits for x=1, y=1
x << (y * 8) == 1 << (1 * 8)
== 1 << 8
== 0x100
*res is an 8-bit value so can only store the bottom 8 bits of this calculation. For any non-zero value of y, the bits which can be stored in *res are guaranteed to be 0.

Resources