Установить определенный бит в байтовом массиве
Я хочу знать, как установить определенный бит в 16-байтовом массиве (128 бит).
Например... если бы я хотел установить 9-й бит в массиве, я бы ожидал:
{00, 80, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}
Если бы я хотел установить 125-й бит...
{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 08}
Я рассмотрел использование сдвига битов, но запутался, как сдвигать биты с массивом, состоящим из 128 битов. Есть ли способ разбить массив такого размера и оценить его в меньших кусках байтов? Любая помощь будет оценена.
6 ответов
Процесс выбора определенного бита состоит из двух этапов:
- Выбор байта, а затем
- Выбираем бит.
Выбор байта прост: все, что вам нужно сделать, это разделить индекс битов на количество бит в байте, то есть разделить на восемь:
int byteIndex = bitIndex / 8;
Теперь, когда вы знаете, какой байт использовать, рассчитайте, какой бит вы хотите получить. Для этого вам нужно вычислить остаток от деления на восемь, например так:
int bitInByteIndex = bitIndex % 8;
С этими двумя индексами легко получить доступ к биту: использовать 1 << bitInByteIndex
как маска, вот так:
byte mask = (byte)(1 << bitInByteIndex);
bool isSet = (bytes[byteIndex] & mask) != 0;
// set to 1
bytes[byteIndex] |= mask;
// Set to zero
bytes[byteIndex] &= ~mask;
// Toggle
bytes[byteIndex] ^= mask;
Вы можете использовать BitArray:
byte[] bytearray = new byte[16];
var bitArray = new BitArray(bytearray);
bitArray.Set(8, true);
bitArray.CopyTo(bytearray, 0);
Непосредственно из Byte Array ваше самое быстрое решение, вероятно, использует BitArray. - http://msdn.microsoft.com/en-us/library/system.collections.bitarray.aspx
Например, это будет что-то вроде:
public void BitManimulation()
{
//Ill just use 2 bytes here for demonstration, get your 16 bytes here.
byte[] bytes = new[] { (byte)250, (byte)250 };
//Convert your bytes to a BitArray.
BitArray array = new BitArray(bytes);
array[3] = !array[3]; // Flip
array[4] = false; // 0
array[5] = true; // 1
//Convert back to bytes.
byte[] bytes2 = new byte[2];
array.CopyTo(bytes2,0);
Console.WriteLine(bytes2[0]);
Console.WriteLine(bytes2[1]);
}
Теперь это идет с ухудшением производительности.
Таким образом, в качестве альтернативы у вас есть BitVector32, который потребует от вас преобразовать блоки по 4 байта в целое число... - http://msdn.microsoft.com/en-us/library/system.collections.specialized.bitvector32.aspx
Наконец, вы можете сделать сдвиг битов, XOR и т. Д., Чтобы получить желаемые результаты. Поскольку @dasblinkenlight уже оставил хороший ответ на этот вопрос, просто оставьте вас с этим для объяснения вещей.
Вот несколько быстрых вспомогательных методов, основанных на его посте:
public static class ByteArrayExt
{
public static byte[] SetBit(this byte[] self, int index, bool value)
{
int byteIndex = index / 8;
int bitIndex = index % 8;
byte mask = (byte)(1 << bitIndex);
self[byteIndex] = (byte)(value ? (self[byteIndex] | mask) : (self[byteIndex] & ~mask));
return self;
}
public static byte[] ToggleBit(this byte[] self, int index)
{
int byteIndex = index / 8;
int bitIndex = index % 8;
byte mask = (byte)(1 << bitIndex);
self[byteIndex] ^= mask;
return self;
}
public static bool GetBit(this byte[] self, int index)
{
int byteIndex = index / 8;
int bitIndex = index % 8;
byte mask = (byte)(1 << bitIndex);
return (self[byteIndex] & mask) != 0;
}
}
Сначала нужно выяснить, с каким байтом вы работаете. Допустим, у вас есть:
00000000 00000000 00000000 00000000 ...
И вы хотите включить 10-й бит, поэтому он должен выглядеть следующим образом:
00000000 01000000 00000000 00000000 ...
Поэтому сначала выполните деление на 8 (округленное в меньшую сторону), чтобы найти номер байта (в данном случае это номер один байт или второй байт). Как только вы это сделаете, вы можете использовать побитовые операторы, чтобы установить нужный бит, т.е.
array[1] |= 0x40
Мы делаем побитовую операцию ИЛИ между старым значением этого байта и 0x40 (который 01000000
). Если старое значение было 00101101
, затем array[1]
знак равно (00101101 OR 01000000)
, который 01101101
,
Естественно, в этом случае я использовал литералы, поэтому вам придется изменить это в зависимости от того, какой бит установлен (например, если вы устанавливаете бит перед последним, вы хотите использовать 0x02
вместо этого и т. д.
Разделив число бит на 8, вы получите байт. Взяв его по модулю 8, вы получите число бит в байте.
Вы также можете использовать lookUp, например:
byte[] lookUp = { 1, 2, 4, 8, 16, 32, 64, 128 };
И следующий код (с учетом обратной битовой нумерации в байтах)
int bytePosition = bitIndex / 8;
int bitInBytePosition = bitIndex % 8;
if (bitIndex < 8)
{
bitInBytePosition = bitIndex;
}
array[bytePosition] ^= lookUp[7 - bitInBytePosition];