Marshal 从 ushort 数组 C# 中读取结构

Marshal Reads a structure from a ushort array C#

我正在尝试从字节数组中读取结构:

var data = new ushort[10]{65535, 65535, 65535 ...};
var datashort = ChangeUshortToShort(data);
FromArray(datashort )

我的结构:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Failures
{
    public ushort cardTrErr;
    public uint TrErr;
    public uint KsrErr;
    public ushort sh6;
    public ushort sh12;
    public ushort blockade;
    public ushort biz;
    public ushort blockadeInPerm;

    public virtual byte[] ToArray()
    {
        int size = Marshal.SizeOf(this);
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(this, ptr, false);
        byte[] array = new byte[size];
        Marshal.Copy(ptr, array, 0, size);
        Marshal.FreeHGlobal(ptr);
        return array;
    }

    public virtual void FromArray(short[] val)
    {
        int size = Marshal.SizeOf(this);
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.Copy(val.ToArray(), 0, ptr, size);
        Marshal.PtrToStructure(ptr, this);
        Marshal.FreeHGlobal(ptr);
    }
    public short[] ChangeUshortToShort(ushort[] val)
    {
        List<short> list = new List<short>();
        foreach (var item in val)
        {
            list.Add((short)(item & 0xFF));
            list.Add((short)(item >> 8));
        }
        return list.ToArray();
    }
}

方法 ChangeUshortToShort return 数组,所有值为 255。

当我执行 ToArray() 时,它变为 return 255。但是如果我执行 FromArray(),它会在应为 65535 时为 ushort 分配 255 值。并在应为 4294967295 时为 uint 分配 16711935。

我想我应该使用属性 MarshalAs,但不知道如何使用。有人可以帮助我吗?

编辑:

第二个结构:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Flags
{
    public ushort frameCnt;
    public ushort progVersion;
    public byte algUM;
    public byte deviceNumber;
    public _alg_1U _alg_1U;
    public ushort OUTPUTS;
    public _statS _StatS1;
    public _statS2 _StatS2;
    //public ushort _StatS1;
    //public ushort _StatS2;
    public ushort nbLector;
    public ushort nbSignal;
    public byte comBlockadeT1;
    public byte comBlockadeT2;
    public _permS permS;
    //public ushort permS;
    public ushort permHistory;
    public ushort stopInfo;
    public _controlFlagsS _controlFlagsS;
    //public ushort _controlFlagsS;
    public ushort timerInfo;
    public ushort timerTrDiagCycle;
    public ushort sizeOfStruct;
    public ushort methanSensorValue1;
    public ushort methanSensorValue2;
    public ushort methanSensorValue3;
    public ushort methanSensorValue4;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _alg_1U
{
    public byte PZP1;
    public byte PZP2;
    public byte PZS;
    public byte PZZ1;
    public byte PZZ2;
    public byte PZZ3;
    public byte KB1;
    public byte KB2;
    public byte KRU;
    public byte reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _statS
{
    public bool SYS_AW;
    public bool SYS_BK;
    public bool SYS_READY;
    public bool SYS_WORK;
    public bool PT_WORK;
    public bool DISPATCHER_ON_LINE;
    public bool SYS_STARTING;
    public bool LEKTOR_ERROR;
    public bool SYS_BK_KSR;
    public bool SYS_READY_LEKTOR;
    public bool SYS_INIT;
    public bool KRU_WORK;
    public bool SIG_RES_DIODA;
    public bool SIG_RES_BK_KSR;
    public bool SIG_RES_WORK;
    public bool unUse16;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _statS2
{
    public bool R1;
    public bool R2;
    public bool SAG_DISABLED;
    public bool unUse4;
    public bool unUse5;
    public bool unUse6;
    public bool unUse7;
    public bool unUse8;
    public bool unUse9;
    public bool unUse10;
    public bool unUse11;
    public bool unUse12;
    public bool unUse13;
    public bool unUse14;
    public bool unUse15;
    public bool unUse16;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _permS
{
    public bool PZP1;
    public bool PZP2;
    public bool PZS;
    public bool PZZ1;
    public bool PZZ2;
    public bool PZZ3;
    public bool KOMBAJN1;
    public bool KOMBAJN2;
    public bool KRU;
    public bool PT;
    public bool unUse11;
    public bool unUse12;
    public bool unUse13;
    public bool unUse14;
    public bool unUse15;
    public bool unUse16;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _controlFlagsS
{
    public bool confSaved;
    public bool confFrameErr;
    public bool confDataErr;
    public bool passSaved;
    public bool passFrameErr;
    public bool unUse6;
    public bool unUse7;
    public bool unUse8;
    public bool unUse9;
    public bool unUse10;
    public bool unUse11;
    public bool unUse12;
    public bool unUse13;
    public bool unUse14;
    public bool unUse15;
    public bool unUse16;
}

如果打算直接重新解释 20 个字节的数据,那么您可能做事很困难;考虑:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Failures
{
    public ushort cardTrErr;
    public uint TrErr;
    public uint KsrErr;
    public ushort sh6;
    public ushort sh12;
    public ushort blockade;
    public ushort biz;
    public ushort blockadeInPerm;
}
static class P
{
    static void Main()
    {
        var data = new ushort[10];
        for (int i = 0; i < data.Length;i++) data[i] = 65535;

        // re-interpret
        Failures failures = MemoryMarshal.AsRef<Failures>(
            MemoryMarshal.Cast<ushort, byte>(data));
        // show the data
        Console.WriteLine(failures.cardTrErr);
        Console.WriteLine(failures.TrErr);
        Console.WriteLine(failures.KsrErr);
        Console.WriteLine(failures.sh6);
        Console.WriteLine(failures.sh12);
        Console.WriteLine(failures.blockade);
        Console.WriteLine(failures.biz);
        Console.WriteLine(failures.blockadeInPerm);
    }
}

但是请注意,像这样重新解释转换是字节顺序的噩梦;值得做一些 CPU-endianness 断言,至少(即如果数据是小端,如果你的 CPU 不是)

如果您无权访问 span,可以通过 unsafe:

获得相同的结果
        Failures failures;
        unsafe
        {
            fixed (ushort* ptr = data)
            {   // re-interpret
                failures = *(Failures*)ptr;
            }
        }
        // show the data
        Console.WriteLine(failures.cardTrErr);
        Console.WriteLine(failures.TrErr);
        Console.WriteLine(failures.KsrErr);
        Console.WriteLine(failures.sh6);
        Console.WriteLine(failures.sh12);
        Console.WriteLine(failures.blockade);
        Console.WriteLine(failures.biz);
        Console.WriteLine(failures.blockadeInPerm);