I have a hex number 0x37 and its binary representation is 0011 0111. How do I access the first 2 bits of the binary representation which is "11"? How do I use bit shifting or masking to achieve this? I can access bit by bit but not two bits at one go?
The smallest group of bits the language allows use to work with is the unsigned char , which is a group of 8 bits.
To read a bit at a specific position, you must mask out all other bits in the value. The operator that assists in that process is the bitwise & (and). After you mask out all the other bits, the value that remains is either zero or some other value.
For accessing a specific bit, you can use Shift Operators . If it is always a 1 that you are going to reset, then you could use an & operation. But, if it can also take 0 value, then & operation will fail as 0 & 1 = 0 . You could use | (OR) during that time.
Bitwise operator works on bits and perform bit by bit operation. Binary AND Operator copies a bit to the result if it exists in both operands. Binary OR Operator copies a bit if it exists in eather operand. Binary XOR Operator copies the bit if it is set in one operand but not both.
If you &
your number with 0x03, you will get the last two bits.
char c = 0x37;
char mask = 0x03;
char lastTwo = c & mask;
Here is a sample to access it bit by bit:
#include <stdio.h>
int main()
{
char byte = 0x37;
int i;
for(i = 7; 0 <= i; i --)
printf("%d\n", (byte >> i) & 0x01);
return 0;
}
You could also use bit-fields to do this. The bad part about bit-fields is that exactly how they work is somewhat compiler-dependent, but if you don't need to port your code to many architectures, maybe it's fine.
Here is an example, written on an Ubuntu Linux computer and tested with GCC.
#include <assert.h>
#include <stdio.h>
#pragma pack(1)
typedef struct
{
unsigned int low2: 2; // 2 bits of the byte
unsigned int high6: 6; // 6 more bits of the byte
} MYBYTE;
typedef union
{
MYBYTE mybyte;
unsigned char b;
} MYUNION;
main()
{
MYUNION m;
assert(sizeof(m) == 1);
m.b = 0x03;
assert(m.mybyte.low2 == 0x03);
assert(m.mybyte.high6 == 0x00);
printf("low2 of 0x03 is: %u\n", m.mybyte.low2);
printf("high6 of 0x03 is: %u\n", m.mybyte.high6);
m.b = 0xff;
printf("low2 of 0x03 is: %u\n", m.mybyte.low2);
printf("high6 of 0x03 is: %u\n", m.mybyte.high6);
assert(m.mybyte.low2 == 0x03);
assert(m.mybyte.high6 == 0x3f);
m.mybyte.high6 = 0x1c;
m.mybyte.low2 = 0x01;
assert(m.b == 0x71);
printf("m.b is: 0x%02x\n", m.b);
return 0;
}
The union is there so we can access it as a full byte, or access it by bit fields. #pragma pack(1)
is there to make sure the bit fields pack down to a byte, with no extra "padding" bits in there. (As I said before, you are relying on implementation details when you use bit fields.)
But look how simple and clean it is to access the bits you want. You can write in a whole byte and read out the bits you want, or write in the bits you want and read out the whole byte.
If you are going to use code like this, it's always a good idea to have some asserts that make sure it is working.
If you are not going to use bit fields, I suggest you define a function that does your shifting and masking for you, to make sure you don't mess up. Maybe something like this:
#include <limits.h>
static unsigned int _bit_masks[] =
{
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
};
#define MIN(a, b) \
((a) < (b) ? (a) : (b))
unsigned int
bits(unsigned int x, unsigned int i_bit, unsigned int c_bits)
{
assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit
assert(i_bit <= 31);
if (i_bit > 31)
return 0;
c_bits = MIN(c_bits, 32 - i_bit);
// shift-and-mask to grab the requested bits, and return those bits
return (x >> i_bit) & _bit_masks[c_bits];
}
You pass in a value, then which bit position you want bits from, and how many bits you want. So to grab 6 bits starting from the bit position 2, with a test value of 0x71 you could call:
x = bits(0x71, 2, 6); // x is set to 0x1c
If you don't like the lookup table, and you want the tiniest code to do this, you can use:
unsigned int
bits(unsigned int x, unsigned int i_bit, unsigned int c_bits)
{
const unsigned int mask_bits = 0xffffffff;
assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit
assert(i_bit <= 31);
if (i_bit > 31)
return 0;
c_bits = MIN(c_bits, 32 - i_bit);
// shift-and-mask to grab the requested bits, and return those bits
return (x >> i_bit) & (mask_bits >> (32 - c_bits));
}
You need to make sure that the mask bits are declared unsigned
because if they are signed, the right-shift operation will sign-extend.
If you declare this last version of the function as inline, put it into header files, and call it with constant values for i_bit
and c_bits
, it will compile down to the minimal code to solve the problem. (For example, if i_bit
is 0, the compiler knows that >> 0
doesn't do anything and will just not generate that code. And if the compiler knows c_bits
as a constant, it can do all the work of shifting mask_bits
at compile time.) But you will need to make sure you are using a version of assert()
that compiles away to nothing in your release build, or else use your own ASSERT()
macro and make your macro compile away to nothing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With