Получить определенный бит из байта

У меня есть байт, в частности один байт из массива байтов, который поступает через UDP, отправленный с другого устройства. Этот байт хранит состояние включения/выключения 8 реле в устройстве.

Как мне получить значение определенного бита в указанном байте? В идеале метод расширения выглядел бы наиболее изящным, и возврат bool имел бы для меня самый лучший смысл.

public static bool GetBit(this byte b, int bitNumber)
{
    //black magic goes here
}

Ответ 1

Легко. Используйте побитовое И, чтобы сравнить ваш номер со значением 2 ^ bitNumber, который можно недорого рассчитать с помощью смещения бит.

//your black magic
var bit = (b & (1 << bitNumber-1)) != 0;

EDIT: Чтобы добавить немного больше деталей, потому что есть много похожих ответов без объяснения:

Побитовое И сравнивает каждое число, побитовое, используя соединение И для создания числа, которое представляет собой комбинацию битов, где были установлены как первый бит, так и второй бит в этом месте. Здесь логическая матрица логики И в "полубайте", которая показывает операцию поразрядного И:

  0101
& 0011
  ----
  0001 //Only the last bit is set, because only the last bit of both summands were set

В вашем случае мы сравниваем число, которое вы передали, с номером, который имеет только бит, который вы хотите найти для набора. Скажем, вы ищете четвертый бит:

  11010010
& 00001000
  --------
  00000000 //== 0, so the bit is not set

  11011010
& 00001000
  --------
  00001000 //!= 0, so the bit is set

Бит-сдвиг, чтобы произвести число, с которым мы хотим сравнить, - это именно то, на что это похоже: возьмите число, представленное как набор бит, и сдвиньте эти биты влево или вправо на определенное количество мест. Поскольку они являются двоичными числами, и поэтому каждый бит является одной большей степенью двух, чем справа, смещение бит влево эквивалентно удвоению числа раз для каждого места, которое сдвинуто, что эквивалентно умножению числа на 2 ^ х. В вашем примере, ищем четвертый бит, мы выполняем:

       1 (2^0) << (4-1) ==        8 (2^3)
00000001       << (4-1) == 00001000

Теперь вы знаете, как это делается, что происходит на низком уровне и почему оно работает.

Ответ 2

В то время как хорошо читать и понимать ответ Джоша, вы, вероятно, будете более счастливы, используя класс Microsoft, предоставленный для этой цели: System.Collections.BitArray Он доступен во всех версиях .NET Framework.

Ответ 3

Это

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

должен это сделать, я думаю.

Ответ 4

другой способ сделать это:)

return ((b >> bitNumber) & 1) != 0;

Ответ 5

Используя BitArray и создавая метод расширения, как предлагает OP:

public static bool GetBit(this byte b, int bitNumber)
{
    System.Collections.BitArray ba = new BitArray(new byte[]{b});
    return ba.Get(bitNumber);
}

Ответ 6

Это работает быстрее, чем 0,1 миллисекунды.

return (b >> bitNumber) & 1;

Ответ 7

попробуйте следующее:

return (b & (1 << bitNumber))>0;

Ответ 8

Метод заключается в использовании другого байта вместе с побитовым И, чтобы замаскировать целевой бит.

Я использовал соглашение из моих классов здесь, где "0" - самый старший бит, а "7" - наименьшее.

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;
    }
}

Ответ 10

Попробуйте выполнить приведенный ниже код. Разница с другими сообщениями заключается в том, что вы можете установить/получить несколько бит с помощью маски (field). Маска для 4-го бита может быть, например, 1 < 3 или 0x10.

    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;
    }

** Пример **

        bool is_ok = 0x01AF.GetBits(0x10); //false
        int res = 0x01AF.SetBits(0x10, true);
        is_ok = res.GetBits(0x10);  // true

Ответ 11

[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);
}