113

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
}
keithwarren7
  • 13,866
  • 8
  • 50
  • 73

10 Answers10

201

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.

KeithS
  • 68,043
  • 20
  • 107
  • 163
  • 11
    Because of missing braces (operator precedence) this code does not compile, it must be `var bit = (b & (1 << bitNumber-1)) != 0`; – bitbonk Aug 30 '12 at 08:44
  • this delivers a result desphased by one bit... the correct solution should be `return (b & (1 << bitNumber)) != 0;` – Paul Efford Jan 14 '22 at 13:54
56

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.

Eonasdan
  • 7,287
  • 8
  • 52
  • 79
Ben Voigt
  • 269,602
  • 39
  • 394
  • 697
  • 2
    This is fabulous but I believe Josh's solution is much faster and more efficient. – Samuel Allan Apr 02 '14 at 18:59
  • 1
    @user2332868: the JIT compiler does specially recognize calls to certain library functions and generate efficient code, but I have no idea if these particular functions get the love. – Ben Voigt Apr 02 '14 at 19:01
  • 1
    well to be sure you can do the same as Josh but in pure inline assembly. But sadly I only program in NASM assembly and don't know about the assembly C# compiles into :(. – Samuel Allan Apr 02 '14 at 19:10
  • 1
    IMHO this kills performance for such a simple task. Using the bitwise operator alternative also gives you a tool that you can use it in almost any language =) – Gaspa79 Apr 13 '17 at 02:04
41

This

public static bool GetBit(this byte b, int bitNumber) {
   return (b & (1 << bitNumber)) != 0;
}

should do it, I think.

23

This is works faster than 0.1 milliseconds.

return (b >> bitNumber) & 1;
asimolmez
  • 622
  • 7
  • 14
10

another way of doing it :)

return ((b >> bitNumber) & 1) != 0;
pierroz
  • 7,285
  • 9
  • 46
  • 60
  • 1
    This won't work: byte b = 1; return ((b >> 1) & 1) != 0 (it's equals to 0) – Rafael Diego Nicoletti Nov 15 '14 at 14:36
  • 1
    Hmmm... I don't get you. If byte b = 1, bit at position 0 is 1, given by (b>>0)&1, and bit at any position greater or equal than 1 is 0, given by (b>>n)&1 where n>=1 as well – pierroz Nov 17 '14 at 15:18
  • I don't believe his does that at all @DavideAndrea, the comment posted by Rafael assumes the right-most bit is bit 1, but PierrOz's code is for when the right most bit is bit 0. If b was 2, then `((2 >> 1)&1)` is `1` and `((2 >> 0)&1)` is `0` because 2 is `00000010` – Cameron Aavik Jan 30 '17 at 01:17
8

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);
}
Jay Walker
  • 4,576
  • 5
  • 46
  • 51
  • 14
    No, please don't create and throw away a BitArray for each bit test. – Ben Voigt Jan 28 '14 at 20:58
  • @BenVoigt, it's an extension method on a byte per OP request. Where do you recommend storing the BitArray instance? – Jay Walker Jan 29 '14 at 07:29
  • 2
    You push back against the request and say, don't call it like a method on the byte, call it on the BitArray. Maybe the byte variable can completely go away. – Ben Voigt Jan 29 '14 at 15:00
  • If you're looking to get the nth bit of a byte you're most likely looking for performance, and this kills it. Otherwise you could always do other unnecessary things like Convert.ToString(num,2)[bitNumber] and get it too. – Gaspa79 Apr 13 '17 at 02:03
5

try this:

return (b & (1 << bitNumber))>0;
Aliostad
  • 78,844
  • 21
  • 155
  • 205
4

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;
    }
}
Sapph
  • 5,998
  • 1
  • 25
  • 31
4

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
John Alexiou
  • 26,060
  • 8
  • 73
  • 128
3
[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);
}
jabukufo
  • 31
  • 1