Вот некоторый непроверенный код.Я уверен, что в нем есть ошибки (всякий раз, когда я пишу такой код, я получаю ошибки, маски и т. Д. Неправильно).Тем не менее, этого должно быть достаточно, чтобы вы начали.Если у вас это работает, и есть только несколько проблем, дайте мне знать в комментариях, и я все исправлю.Если вы не можете заставить его работать, дайте мне знать, и я удалю ответ.Если это требует серьезной перезаписи, опубликуйте свой рабочий код в качестве ответа и дайте мне знать.
Еще одна вещь, о которой следует позаботиться об этом (поскольку вы упомянули, что это из файла), это 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;
}
}
Я надеюсь, что это полезно.Дайте мне знать.