Marshal 从 ushort 数组 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,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(),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 返回所有值为 255 的数组。

当我执行 ToArray() 时返回 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 端序断言,至少(即,如果数据是小端序的,如果您的 CPU 不是,则抛出异常) >

如果您无法访问跨度,则可以通过 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);