Как я могу преобразовать биты в байты?
-
23-08-2019 - |
Вопрос
У меня есть массив из 128 логических значений, которые представляют биты.Как я могу преобразовать эти 128-битные представления в 16 байт?
Пример:
У меня есть массив, который выглядит следующим образом:
0110001100110000100010111011001011010011010001010001101101001100
1000010000000000001000111111111101000011111001111011111011111001
(Преобразовано в 1s и 0s для большей краткости)
Мне нужно преобразовать эти биты в следующий массив байтов:
99 48 139 178 211 69 27 76 132 0 35 255 67 231 190 249
Редактировать:Похоже, это не работает:
public byte[] ToByteArray() {
int numBytes = Count / 8;
if (_bits.Count % 8 != 0) numBytes++;
byte[] bytes = new byte[numBytes];
int byteIndex = 0, bitIndex = 0;
for (int i = 0; i < _bits.Count; i++) {
if (_bits[i])
bytes[byteIndex] |= (byte)(1 << bitIndex);
bitIndex++;
if (bitIndex == 8) {
bitIndex = 0;
byteIndex++;
}
}
return bytes;
}
Это выводит:
198 12 209 77 203 162 216 50 33 0 196 255 194 231 125 159
Решение
Код обрабатывает первый бит как младший бит слова, так что в итоге каждое слово будет перевернуто.В качестве быстрого и грязного решения попробуйте следующее:
bytes[byteIndex] |= (byte)(1 << (7-bitIndex));
Это помещает первый бит в массиве на самую высокую позицию в первом байте и т.д.
Другие советы
Я не знаю, есть ли автоматический способ сделать это, но вы можете сделать это с помощью простого алгоритма.
Простой алгоритм:
Создайте массив байтов, который будет использоваться в качестве вашего выходного буфера, и инициализируйте все байты равными 0.Размер этого массива должен основываться на длине вашего входного логического массива:ceil(bool_array_length / 8.0)
Объявите переменную index, которая будет использоваться в качестве вашего текущего байта, и установите для нее значение 0.Это удерживает индекс в вашем выходном буфере.
Выполните итерацию по каждому элементу в вашем входном логическом массиве.
3.1.Левый бит сдвигает число 1 на индекс массива mod 8.Назовите этот номер своей маской.
3.2.Вычислите ваш байтовый индекс как ваш текущий индекс в массиве div 8.
3.3.Если у вас есть логическоеtrue
укажите текущий индекс в вашем входном логическом массиве, выполнитеbitwise OR
с вашим текущим байтом и вашей маской.
bool[] bools = ...
BitArray a = new BitArray(bools);
byte[] bytes = new byte[a.Length / 8];
a.CopyTo(bytes, 0);
Редактировать:На самом деле это также возвращает:
198 12 209 77 203 162 216 50 33 0 196 255 194 231 125 159
Неправильный порядковый номер?Я все равно оставлю ответ для справки.
Редактировать:Вы можете использовать BitArray.CopyTo(), перевернув массивы следующим образом:
bool[] bools = ...
Array.Reverse(bools); // NOTE: this modifies your original array
BitArray a = new BitArray(bools);
byte[] bytes = new byte[a.Length / 8];
a.CopyTo(bytes, 0);
Array.Reverse(bytes);
Попробуйте эту функцию (написанную как метод расширения).
public byte[] ToByteArray(this bool[] bits)
{
var bytes = new byte[bits.Length / 8];
for (int i = 0, j = 0; j < bits.Length; i++, j += 8)
{
// Create byte from bits where LSB is read first.
for (int offset = 0; offset < 8; offset++)
bytes[i] |= (bits[j + offset] << offset);
}
return bytes;
}
Примечание:Это приведет к сбою, если количество битов (bools) не кратно 8, но, судя по вашему вопросу, это не так.Потребовалась бы лишь очень небольшая модификация, чтобы разрешить использование битовых массивов любой длины.
private static byte[] GetBytes(string bitString)
{
byte[] result = Enumerable.Range(0, bitString.Length / 8).
Select(pos => Convert.ToByte(
bitString.Substring(pos * 8, 8),
2)
).ToArray();
List<byte> mahByteArray = new List<byte>();
for (int i = result.Length - 1; i >= 0; i--)
{
mahByteArray.Add(result[i]);
}
return mahByteArray.ToArray();
}
private static String ToBitString(BitArray bits)
{
var sb = new StringBuilder();
for (int i = bits.Count - 1; i >= 0; i--)
{
char c = bits[i] ? '1' : '0';
sb.Append(c);
}
return sb.ToString();
}