Скопируйте биты в правильном порядке - PullRequest
0 голосов
/ 30 января 2019

Чтобы проанализировать двоичный поток неуправляемых данных, мне нужно воссоздать типы данных.Данные сжимаются, что означает, что я читаю 2 байта, которые на самом деле представляют 6-битное byte значение и 10-битное short значение.

Все, что мне нужно сделать, это скопировать битовую последовательность из одногоценность для другого.Я знаю начальный бит и длину для исходного значения и конечного значения.До сих пор я сделал два подхода, которые оба копируют правильные биты, но как-то в обратном порядке.

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount)
{
    short result = 0;
    for (int i = 0; i < bitCount; i++)
        //result |= (byte) (value & (1 << sourceStartBit + i) | (result & (1 << (destStartBit + bitCount) - i)));
        result |= (short) (value & (1 << sourceStartBit + i));

    return (byte) (result >> ((destStartBit - bitCount) + sizeof(byte) * 8));
}

Для моего тестового сценария я использую короткое замыкание со следующим значением:

0000 0000 1101 0011
^15               ^0

Моя цель - скопировать 4-й - 7-й бит этой короткой строки в 0-3-й бит байта.

Когда я использую подход закомментированной строки (без кода в предложении возврата) или способ, которым она в настоящий момент выделена, я всегда получаю такой результат:

0000 1011
^7      ^0

Так что я хочу, просто наоборот.Я уверен, что это что-то крошечное, но что я здесь пропускаю?Я не понимаю, почему это меняет порядок.Подход со сдвигом битов (прямое копирование по битам и смещение его в правильную позицию) не должен его менять, не так ли?

EDIT : метод всегда имеетвход типа short.У меня есть 3 параметра: sourceStart , который является битом, который я начинаю копировать из входного значения (от низкого до высокого), destStart , который является битом, который я копирую в мой пункт назначения (который являетсялибо байтовый, либо короткий - я бы сделал для этого два конкретных метода) и bitCount , то есть количество бит (начиная с младшего до старшего разряда), которое я хочу скопировать.

Метод должны копировать биты в правильном порядке.Так, например, CopyBitwise(input, 4, 0, 4) должен вернуть (влево: высокий, правый: младший порядок) 0000 1011 с учетом этого ввода:

input [short]: ... 1011 0110
                   ^8th    ^0th

Еще один:

input [short]: 1011 0110 0100 0111
               ^15th             ^0th
                    ^end ^start

CopyBitwise(input, 7, 3, 5) долженрезультат в

0011 0000
^8th    ^0th
^end ^start

Ответы [ 3 ]

0 голосов
/ 30 января 2019

Похоже, что вы хотите вырезать подпоследовательность данного короткого.Это может быть достигнуто путем маскирования .Если вы хотите вырезать подсвеченные биты из следующей битовой последовательности: 1011 011001000111, вы можете сделать это, & пометив ее с помощью 0000 0000 1111 0000.

  1011 0110 0100 0111
& 0000 0000 1111 0000
= 0000 0000 0100 0000

Затем можно сдвинуть результирующие биты, чтобы ваши биты с маской начинались в нужном месте (здесь 1):

  0000 0000 0100 0000 >>
 · 0000 0000 0100 000 >>
 ·· 0000 0000 0100 00 >>
 ··· 0000 0000 0100 0

Чтобы сделать этоконкретнее, вот код:

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount)
{
    ushort mask = 0; //Start with 0
    mask = (ushort)~mask; //Invert to get all 1s
    mask >>= sizeof(ushort)*8 - bitCount; //Shift right, until we have bitCount bits left
    mask <<= sourceStartBit; //Shift back left, to make sure the bits are in the right place

    ushort result = (ushort)value;
    result &= mask; //Mask out the bits we want

    //Shift the remaining bits into the desired position
    if (sourceStartBit < destStartBit)
    {
        result <<= destStartBit - sourceStartBit;
    }
    else
    {
        result >>= sourceStartBit - destStartBit;
    }
    return (byte)result;
}

Разбивка кода:

Сначала мы собираем битовую маску.Для этого мы начинаем с 0, а затем инвертируем все биты, чтобы получить все биты.Мы могли бы начать с 0xFFFF, но таким образом код все равно будет работать, если вы переключитесь на вход другой длины.

Затем мы смещаем нашу маску, пока не останется только bitCount 1 s.Для этого шага важно, чтобы наша маска имела тип unsigned integer.Если бы вы использовали значение со знаком, битовое смещение сместилось бы в новые 1 с слева.

Чтобы закончить нашу маску, мы сдвигаем ее назад влево, чтобы правильно ее расположить.

Далее, мы применяем маску к нашему значению, чтобы вырезать ненужные биты.

Наконец, мы сдвигаем результат в нужную позицию;здесь снова важно использовать беззнаковые сдвиги, чтобы убедиться, что ошибочные 1 s не сдвинуты влево.


Вот пример того, что происходит при вызове методас аргументами (0b1011_0110_0100_0111, 7, 3, 5), как во втором примере.

mask:
  0000 0000 0000 0000  ~x
= 1111 1111 1111 1111  x>>(16 - 5)
= 0000 0000 0001 1111  x<<7
= 0000 1111 1000 0000

result:
  1011 0110 0100 0111  x&mask
  0000 0110 0000 0000  x>>(7-3)
  0000 0000 0110 0000

РЕДАКТИРОВАТЬ 1: Исправил эту строку mask >>= bitCount - sizeof(ushort)*8; в коде до mask >>= sizeof(ushort)*8 - bitCount;.

РЕДАКТИРОВАТЬ 2: Я также испортил строку прямо внизу, исправил это тоже.Это то, что я получаю за тестирование только одного случая.

РЕДАКТИРОВАТЬ 3: Добавлен пошаговый пример.

0 голосов
/ 30 января 2019

Это должно работать правильно.Сначала создайте маску для нужных вам бит, а затем переместите их в нужное место.Обратите внимание, что сдвиг выполняется в два хода, поскольку оператор сдвига должен быть положительным числом.

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount)
{
  short mask = (short)((0xFFFF >> (16-bitCount)) << sourceStartBit);
  short result = (short)(((value & mask) >> sourceStartBit) << destStartBit);
  return (byte)result;
}
0 голосов
/ 30 января 2019

Вам не нужна петля для этого!Это должно сделать трюк:

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount){
    byte result = (byte) ((value >> sourceStartBit) << destStartBit);
    result &= (byte) ~(0xff << bitCount); // mask for zeros at the left of result
    return result;
}
...