C # извлекает диапазоны битов из массива байтов - PullRequest
0 голосов
/ 03 апреля 2019

Мне нужно извлечь некоторые битовые диапазоны из 16-байтового значения, например ::100100

bit 0 = first thing
next 54 bits = second thing
next 52 bits = third thing
last 21 bits = fourth thing

.net не имеет структуры UInt128, ну, у него есть класс BigInteger, но я не уверен, что это правильно для работы, может быть, это так?

Я обнаружил стороннюю библиотеку, которая может считывать биты из потока, но при попытке преобразовать их обратно в UInt64 с использованием BitConverter произойдет сбой, поскольку 54 бита недостаточно для UInt64, но это слишком долго для UInt32

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

Любые предложения или комментарии будут оценены.

1 Ответ

0 голосов
/ 04 апреля 2019

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

Еще одна вещь, о которой следует позаботиться об этом (поскольку вы упомянули, что это из файла), это endian-Несс .Не все компьютерные архитектуры представляют значения одинаково.Я оставлю вам любой байт swizzling (при необходимости).

Во-первых, структуры в C ++ в основном такие же, как классы (хотя люди думают, что они разные).В C # они очень разные.Структура в C # является типом значения .Когда вы делаете присваивание типа значения, компилятор делает копию значения структуры, а не просто копирует ссылку на объект (как это делается с классами).Типы значений имеют неявный конструктор по умолчанию, который инициализирует все члены их значениями по умолчанию (ноль или ноль).

Маркировка структуры с помощью [StructLayout(LayoutKind.Sequential)] указывает компилятору размещать элементы в указанном порядке (компилятор не 'должны нормально).Это позволяет вам передавать ссылку на один из них (через P / Invoke ) в программу на C, если вы хотите.

Итак, моя структура начинается следующим образом:

[StructLayout(LayoutKind.Sequential)]
public struct Struct128
{
    //not using auto-properties with private setters on purpose.
    //This should look like a single 128-bit value (in part, because of LayoutKind.Sequential)
    private ulong _bottom64bits;
    private ulong _top64bits;
}

Теперь я собираюсь добавить членов в эту структуру.Поскольку вы получаете 128 бит из файла, не пытайтесь читать данные в единую 128-битную структуру (если вы можете понять, как (посмотрите сериализацию), вы можете, но ...).Вместо этого читайте 64 бита за раз и используйте конструктор, подобный этому:

 public Struct128(ulong bottom64, ulong top64)
 {
     _top64bits = top64;
     _bottom64bits = bottom64;
 }

Если вам нужно записать данные одного из них обратно в файл, перейдите к получению 64-битного за разиспользуя свойства только для чтения, такие как:

//read access to the raw storage
public ulong Top64 => _top64bits;
public ulong Bottom64 => _bottom64bits;

Теперь нам нужно получить и установить различные значения битовой разрядности из нашей структуры.Получение (и настройка) первой вещи очень просто:

public bool FirstThing
{
    get => (_bottom64bits & 0x01) == 1;
    set
    {
        //set or clear the 0 bit
        if (value)
        {
            _bottom64bits |= 1ul;
        }
        else
        {
            _bottom64bits &= (~1ul);
        }
    }
}

Получение / установка второй и четвертой вещей очень похожи.В обоих случаях, чтобы получить значение, вы маскируете все, кроме важных битов, а затем сдвигаете результат.Чтобы установить значение, вы берете значение свойства, сдвигаете его в нужное место, обнуляете биты в соответствующем (верхнем или нижнем) значении, сохраненном в структуре, и ИЛИ в новых битах (которые вы устанавливаете путем сдвига)

//bits 1 through 55
private const ulong SecondThingMask = 0b111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1110;

public ulong SecondThing
{
    get => (_bottom64bits & SecondThingMask) >> 1;
    set
    {
        var shifted = (value << 1) & SecondThingMask;
        _bottom64bits = (_bottom64bits & (~SecondThingMask)) | shifted;
    }
}

и

 //top 21 bits
 private const ulong FourthThingMask = 0b1111_1111_1111_1111_1111_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
 //to shift the top 21 bits down to the bottom 21 bits, need to shift 64-21
 private const int FourthThingShift = 64 - 21;

 public uint FourthThing
 {
     get => (uint)((_top64bits & FourthThingMask) >> FourthThingShift);
     set
     {
         var shifted = ((ulong)value << FourthThingShift) & FourthThingMask;
         _top64bits = (_top64bits & (~FourthThingMask)) | shifted;
     }
 }

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

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

 //the third thing is the hard part.  
 //The bottom 55 bits of the _bottom64bits are dedicate to the 1st and 2nd things, so the next 9 are the bottom 9 of the 3rd thing
 //The other 52-9 (=43) bits come-from/go-to the _top64bits

 //top 9 bits
 private const ulong ThirdThingBottomMask = 0b1111_1111_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
 //bottom 43 bits
 private const ulong ThirdThingTopMask = 0b111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111;
 private const int ThirdThingBottomShift = 64 - 9;

 //bottom 9 bits
 private const ulong ThirdThingBottomSetMask = 0b1_1111_1111;
 //all but the bottom 9 bits
 private const ulong ThirdThingTopSetMask = 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1110_0000_0000;
 //52 bits total
 private const ulong ThirdThingOverallMask = 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111;

 public ulong ThirdThing
 {
     get
     {
         var bottom = (_bottom64bits & ThirdThingBottomMask) >> ThirdThingBottomShift;
         var top = (_top64bits & ThirdThingTopMask) << 9;
         return top | bottom;
     }
     set
     {
         var masked = value & ThirdThingOverallMask;
         var bottom = (masked & ThirdThingBottomSetMask) << ThirdThingBottomShift;
         _bottom64bits = (_bottom64bits & (~ThirdThingBottomSetMask)) | bottom;
         var top = (masked & ThirdThingTopSetMask) >> 9;
         _top64bits = (_top64bits & (~ThirdThingTopSetMask)) | top;
     }
 }

Я надеюсь, что это полезно.Дайте мне знать.

...