У меня следующая ситуация:
struct object1 {
bool a:1;
bool b:1;
uint8_t c:2;
bool d:1;
abc e:3;
uint16_t header;
uint8_t footer;
uint8_t mid[4];
}
Возможно, я не знаю синтаксис, но в C # играть с битами не так просто, как в C ++. Я использовал классы BitArray и BitConverter для создания методов для заполнения данных, но столкнулся с проблемой:
object1 * rqr = (object1 *) &Msg.Data[2];
В основном они приводят объект к массиву байтов. Каждый поиск, который я проводил, кричит по сериализации, но чтобы действительно преобразовать вышеуказанную строку, у меня не может быть никаких дополнительных метаданных или чего-либо еще.
Я действительно хочу создать указатель на место в памяти и «привести» это место к указанному объекту. Это возможно? Если нет, есть ли решение этой проблемы? Я не могу себе представить, что битовые манипуляции на этом уровне полностью исключены. Я бы по умолчанию для меня просто не зная, прежде чем принять это.
Редактировать::
Я понимаю, что C # не позволяет указатели на типы управления. Я спрашиваю, есть ли способ сказать:
Byte[] ayData = new Byte[8];
ObjectOfSize8 nObject = (ObjectOfSize8)ayData;
Я понимаю, что вышесказанное не сработает, но есть ли в языке что-то, что позволит приводить данные, если вы достаточно умны, чтобы понимать размеры памяти объектов?
Вы не можете делать то, что просите, с приведением типов в C #. Я подозреваю, что самый простой способ сделать то, что вам нужно, это закрепить структуру C #. Затем у вас есть IntPtr, который вы можете использовать с Marshal.Copy для копирования в и из байтового массива.
Что касается битовых полей, ими нужно будет управлять с помощью операций побитового сдвига, побитового ИЛИ и побитового И.
Вы можете решить проблему с битовым полем с помощью структуры, которая обрабатывает битовый сдвиг и маскировку для вас:
[StructLayout(LayoutKind.Sequential, Size=1)]
public struct BitField8
{
private byte _bits;
private static readonly byte[] Masks = new byte[] { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
public BitField8(int val)
{
_bits = (byte) val;
}
public byte Get(int bit, int length = 1)
{
int shift = bit + length - 1;
return (byte) ((_bits >> shift) & Masks[length-1]);
}
public void Set(int bit, int length, int val)
{
int mask = Masks[length-1];
int shift = bit + length - 1;
val = (val & mask) << shift;
mask = ~(mask << shift);
_bits = (byte)((_bits & mask) | val);
}
}
Итак, в вашем примере:
bool a:1;
bool b:1;
uint8_t c:2;
bool d:1;
abc e:3;
Вы бы установили a
позвонив Set(0, 1, 1)
(установите значение 1).
Дать c
значение 3, вы бы назвали Set(3, 2, 3)
, (c
занимает биты 2 и 3).
Это в основном дублирует функциональность битовых полей C ++, хотя я допускаю, что у меня неправильный порядок битов. Я действительно не знаю, поставил ли компилятор C ++ a
в бите 0 или в бите 7.
Вы можете сделать что-то подобное с 16-битными, 32-битными и 64-битными битовыми полями.
Итак, ваша структура будет содержать:
BitField8 myBitfield;