Get a specific bit from byte
C#C# Problem Overview
I have a byte, specifically one byte from a byte array which came in via UDP sent from another device. This byte stores the on/off state of 8 relays in the device.
How do I get the value of a specific bit in said byte? Ideally an extension method would look the most elegant and returning a bool would make the most sense to me.
public static bool GetBit(this byte b, int bitNumber)
{
//black magic goes here
}
C# Solutions
Solution 1 - C#
Easy. Use a bitwise AND to compare your number with the value 2^bitNumber, which can be cheaply calculated by bit-shifting.
//your black magic
var bit = (b & (1 << bitNumber-1)) != 0;
EDIT: To add a little more detail because there are a lot of similar answers with no explanation:
A bitwise AND compares each number, bit-by-bit, using an AND join to produce a number that is the combination of bits where both the first bit and second bit in that place were set. Here's the logic matrix of AND logic in a "nibble" that shows the operation of a bitwise AND:
0101
& 0011
----
0001 //Only the last bit is set, because only the last bit of both summands were set
In your case, we compare the number you passed with a number that has only the bit you want to look for set. Let's say you're looking for the fourth bit:
11010010
& 00001000
--------
00000000 //== 0, so the bit is not set
11011010
& 00001000
--------
00001000 //!= 0, so the bit is set
Bit-shifting, to produce the number we want to compare against, is exactly what it sounds like: take the number, represented as a set of bits, and shift those bits left or right by a certain number of places. Because these are binary numbers and so each bit is one greater power-of-two than the one to its right, bit-shifting to the left is equivalent to doubling the number once for each place that is shifted, equivalent to multiplying the number by 2^x. In your example, looking for the fourth bit, we perform:
1 (2^0) << (4-1) == 8 (2^3)
00000001 << (4-1) == 00001000
Now you know how it's done, what's going on at the low level, and why it works.
Solution 2 - C#
While it's good to read and understand Josh's answer, you'll probably be happier using the class Microsoft provided for this purpose: System.Collections.BitArray It's available in all versions of .NET Framework.
Solution 3 - C#
This
public static bool GetBit(this byte b, int bitNumber) {
return (b & (1 << bitNumber)) != 0;
}
should do it, I think.
Solution 4 - C#
This is works faster than 0.1 milliseconds.
return (b >> bitNumber) & 1;
Solution 5 - C#
another way of doing it :)
return ((b >> bitNumber) & 1) != 0;
Solution 6 - C#
Using BitArray class and making an extension method as OP suggests:
public static bool GetBit(this byte b, int bitNumber)
{
System.Collections.BitArray ba = new BitArray(new byte[]{b});
return ba.Get(bitNumber);
}
Solution 7 - C#
try this:
return (b & (1 << bitNumber))>0;
Solution 8 - C#
The method is to use another byte along with a bitwise AND to mask out the target bit.
I used convention from my classes here where "0" is the most significant bit and "7" is the least.
public static class ByteExtensions
{
// Assume 0 is the MSB andd 7 is the LSB.
public static bool GetBit(this byte byt, int index)
{
if (index < 0 || index > 7)
throw new ArgumentOutOfRangeException();
int shift = 7 - index;
// Get a single bit in the proper position.
byte bitMask = (byte)(1 << shift);
// Mask out the appropriate bit.
byte masked = (byte)(byt & bitMask);
// If masked != 0, then the masked out bit is 1.
// Otherwise, masked will be 0.
return masked != 0;
}
}
Solution 9 - C#
Try the code below. The difference with other posts is that you can set/get multiple bits using a mask (field
). The mask for the 4th bit can be 1<<3, or 0x10, for example.
public int SetBits(this int target, int field, bool value)
{
if (value) //set value
{
return target | field;
}
else //clear value
{
return target & (~field);
}
}
public bool GetBits(this int target, int field)
{
return (target & field) > 0;
}
** Example **
bool is_ok = 0x01AF.GetBits(0x10); //false
int res = 0x01AF.SetBits(0x10, true);
is_ok = res.GetBits(0x10); // true
Solution 10 - C#
[Flags]
enum Relays : byte
{
relay0 = 1 << 0,
relay1 = 1 << 1,
relay2 = 1 << 2,
relay3 = 1 << 3,
relay4 = 1 << 4,
relay5 = 1 << 5,
relay6 = 1 << 6,
relay7 = 1 << 7
}
public static bool GetRelay(byte b, Relays relay)
{
return (Relays)b.HasFlag(relay);
}