Аналог структуры C++ с битовыми полями в C#

90
12 апреля 2021, 06:10

Объясните, выделяется размер для следующей структуры

struct BURInSyncStruct
{
    uint16_t Sync1 : 12;
    uint16_t Sync2 : 12;
    uint16_t Sync3 : 12;
    uint16_t Sync4 : 12;
} __attribute__((packed));

и как записать такую структуру на C#? Я пытался записать следующим образом

[StructLayout(LayoutKind.Explicit)]
struct BURInSyncStruct
{
    [FieldOffset(0)]
    public ushort Sync1;
    [FieldOffset(1)]
    public ushort Sync2;
    [FieldOffset(2)]
    public ushort Sync3;
    [FieldOffset(3)]
    public ushort Sync4;
} 

но, мне кажется, это не верно.

Answer 1

Естественно, это неверно. В С++ 4 битовых поля по 12 бит, расположенных вплотную без пропусков ( __attribute__((packed))). В вашем объявлении для С# 4 обыкновенных поля ushort, накладывающихся друг на друга. Как сделать правильно? В C# нет битовых полей, но есть класс BitConverter и битовые операции, которые позволяют реализовать их.

Битовые маски для установки полей Sync1 и Sync2 выглядят так:

Байт №: |       5|       4|       3|       2|       1|       0| 
                                             00001111 11111111   = 0x0FFF
                                                   Sync1
Байт №: |       5|       4|       3|       2|       1|       0|
                                    11111111 11110000 00000000   = 0xFFF000
                                          Sync2

Это приводит нас к такому коду:

[StructLayout(LayoutKind.Sequential)]
public struct BURInSyncStruct
{
    public static BURInSyncStruct Create()
    {
        BURInSyncStruct s = new BURInSyncStruct();
        s.data = new byte[6];
        return s;
    }
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public byte[] data;                       
    public ushort Sync1
    {
        get
        {                    
            byte[] bytes64 = new byte[8];
            Array.Copy(data, bytes64, data.Length);
            ulong x = BitConverter.ToUInt64(bytes64, 0);
            ulong y = x & 0x0FFF;                    
            return (ushort)y;
        }
        set
        {
            byte[] bytes64 = new byte[8];
            Array.Copy(data, bytes64, data.Length);
            ulong x = BitConverter.ToUInt64(bytes64, 0);
            x = x & ~((ulong)0x0FFF);
            ulong y = (ulong)value & 0x0FFF;
            ulong res = x | y;
            bytes64 = BitConverter.GetBytes(res);
            Array.Copy(bytes64, data, data.Length);
        }
    }
    public ushort Sync2
    {
        get
        {
            byte[] bytes64 = new byte[8];
            Array.Copy(data, bytes64, data.Length);
            ulong x = BitConverter.ToUInt64(bytes64, 0);
            ulong y = x & 0xFFF000;
            y = y >> 12;                       
            return (ushort)y;
        }
        set
        {
            byte[] bytes64 = new byte[8];
            Array.Copy(data, bytes64, data.Length);
            ulong x = BitConverter.ToUInt64(bytes64, 0);
            x = x & ~((ulong)0xFFF000);
            ulong y = (ulong)(value << 12) & 0xFFF000;                    
            ulong res = x | y;
            bytes64 = BitConverter.GetBytes(res);
            Array.Copy(bytes64, data, data.Length);
        }
    }

}
READ ALSO
Подзапрос в Linq

Подзапрос в Linq

БД: MS SQL Server Express 2017 Бэкенд: Asp net mvc

107
entity framework Загрузка связанных данных

entity framework Загрузка связанных данных

у меня есть две таблицы(phone, purchase) которые связаны между собой и я хочу что бы в Informationcshtml выводилось связанные данные,я пробовал ,но не получается,...

85
Есть ли иной подход получения информации при помощи TCP в C#?

Есть ли иной подход получения информации при помощи TCP в C#?

Я использую следующий код для получения массива байт:

89
App.Run в ASP.NET Core

App.Run в ASP.NET Core

Столкнулся со следующей проблемойУ метанита видел, как устанавливать куки, сделал следующим образом:

73