c# - Get Specific Bit and Get first 14 bits of a u

2019-06-14 15:35发布

问题:

After reading all of the questions and answers on bit shifting/masking, I simply cannot wrap my head around it. I'm just not understanding how it works on a fundamental level. I've been able to achieve various techniques by using BitArray and BitConverter instead, but I really would like to understand bit shifting/masking better.

The specific need I have is to do the following:

I have a ushort: 0x810E (33038)

Using bit shifting/masking, I'd like to know how to:

  • Get the 16th bit Result: 1
  • Get the 15th bit Result: 0
  • Get a range of bits to create a new ushort value, specifically the first 14 bits Result: 270

As I said, I'm able to perform these tasks using BitArray which is how I've gotten the correct results, but I'd like to understand how to perform these operations using bit shifting/masking.

Any help would be appreciated.

回答1:

Masking single bits

As you probably know, ushort is a 16-bit value, so your given number 0x810E can also be written as

‭10000001 00001110‬

Because there is no shifting operator for ushort, the value is first converted to int.

So, if you want to get the 15th bit, you can take a single bit

000000000 0000000 00000000 00000001

and shift it 14 times to the left (right side is filled with 0)

00000000 00000000 01000000 00000000

and you have created a bitmask.

Now if you combine mask and value with an bitwise and, you'll get only the value of the 15th bit:

  ‭00000000 00000000 10000001 00001110‬
& 00000000 00000000 01000000 00000000
= 00000000 00000000 00000000 00000000

which is 0 again. To access this bit, you'll have to shift the whole result back to the right 14 times and cast it to a ushort.

This can be expressed with the following code:

ushort value_15 = (ushort)(((1 << 14) & value) >> 14);

Can we do better?

Although this approach seems to be correct, but there is a simpler way to do this: shift the original value to the right 14 times (result is 00000000 00000000 00000000 00000010, left side is filled with 0) and perform a simple bitwise & with 1:

  00000000 00000000 00000000 00000000 00000000 00000010 
& 00000000 00000000 00000000 00000000 00000000 00000001
= 00000000 00000000 00000000 00000000 00000000 00000000

This results in C# in:

ushort value_15 = (ushort)((value >> 14) & 1);

So you avoid one additional shift and we get the same results even when using signed numbers (because there the highest bit, used for the sign, is left unchanged by shifting).

Masking a bit range

To mask a bit range, all you have to do is to change your mask. So, to get the value of the lower 14 bits you can use the mask

  00000000 00000000 ‭10000001 00001110‬
& 00000000 00000000 00111111 11111111
= 00000000 ‭00000000 00000001 00001110

In C# this can be expressed with

ushort first14bits = (ushort)((0xFFFF >> 2) & value);

where (0xFFFF is 00000000 00000000 11111111 11111111).