Получить определенный бит из байта
У меня есть байт, в частности один байт из массива байтов, который пришел через UDP, отправленный с другого устройства. Этот байт сохраняет состояние включения / выключения 8 реле в устройстве.
Как мне получить значение определенного бита в байте? В идеале метод расширения будет выглядеть наиболее элегантно и возврат bool имеет смысл для меня.
public static bool GetBit(this byte b, int bitNumber)
{
//black magic goes here
}
11 ответов:
легко. Используйте побитовое число и сравните свое число со значением 2^bitNumber, которое можно дешево вычислить путем сдвига битов.
//your black magic var bit = (b & (1 << bitNumber-1)) != 0;
EDIT: чтобы добавить немного больше деталей, потому что есть много подобных ответов без объяснения причин:
побитовое и сравнивает каждое число, бит за битом, используя AND join для получения числа, которое является комбинацией битов, где были установлены как первый бит, так и второй бит в этом месте. Вот логическая матрица и логики в "грызть", что показывает работу побитового и:
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^x. в вашем примере, ища четвертый бит, мы выполняем:
1 (2^0) << (4-1) == 8 (2^3) 00000001 << (4-1) == 00001000
теперь вы знаете, как это делается, что происходит на низком уровне, и почему это работает.
хотя хорошо читать и понимать ответ Джоша, вы, вероятно, будете счастливее, используя класс Microsoft, предоставленный для этой цели:
этой
public static bool GetBit(this byte b, int bitNumber) { return (b & (1 << bitNumber)) != 0; }
должен сделать это, я думаю.
С помощью BitArray класс и создание метода расширения, как предлагает OP:
public static bool GetBit(this byte b, int bitNumber) { System.Collections.BitArray ba = new BitArray(new byte[]{b}); return ba.Get(bitNumber); }
метод состоит в том, чтобы использовать другой байт вместе с побитовым и замаскировать целевой бит.
я использовал соглашение из моих классов здесь, где" 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; } }
этот сайт имеет несколько реализаций, как получить бит из байта в C#. Она также имеет довольно хорошее объяснение этого. http://bytes.com/topic/c-sharp/answers/505085-reading-bits-byte-file
попробуйте код ниже. Разница с другими сообщениями заключается в том, что вы можете установить/получить несколько битов с помощью маски (
field
). Маска для 4-го бита может быть 1public 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