如何将C#字节数组转换为结构化数据?

我通过USB将64字节数据包传递给微控制器。 在微控制器的C代码中,数据包具有结构,

typedef union
{
    unsigned char data[CMD_SIZE];
    cmd_get_t get;
    // plus more union options
} cmd_t;

typedef struct
{
    unsigned char cmd;          //!< Command ID
    unsigned char id;           //!< Packet ID
    unsigned char get_id;       //!< Get identifier
    unsigned char rfu[3];       //!< Reserved for future use
    union
    {
        unsigned char data[58];     //!< Generic data
        cmd_get_adc_t adc;          //!< ADC data
        // plus more union options
    } data;                     //!< Response data
} cmd_get_t;

typedef struct
{
    int16_t supply;
    int16_t current[4];
} cmd_get_adc_t;

在C#的PC端,我提供了一个函数,它返回64字节的数据包作为字节[]。 该函数使用Marshal.Copy将接收到的数据复制到Byte []数组中。 然后我使用了表单的C#结构

[StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct COMMAND_GET_ADC
    {
        public byte CommandID;
        public byte PacketID;
        public byte GetID;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
            public byte[] RFU;
        public short Supply;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
            public short[] Current;
    }

并再次使用Marshal.Copy将字节数组复制到结构中,以便我可以使用结构化数据,例如

COMMAND_GET_ADC cmd = (COMMAND_GET_ADC)RawDeserialize(INBuffer, 1, typeof(COMMAND_GET_ADC));
short supply = cmd.Supply;

public static object RawDeserialize(Byte[] rawData, int position, Type anyType)
{
    int rawsize = Marshal.SizeOf(anyType);
    if(rawsize > rawData.Length)
    {
        return null;
    }
    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(rawData, position, buffer, rawsize);
    object retobj = Marshal.PtrToStructure(buffer, anyType);
    Marshal.FreeHGlobal(buffer);
    return retobj;
}

这只是感觉我正在制作大量的数据副本,并且喜欢它可能不是实现我想要的最有成效的方式。 我还需要将结构化数据转换回到设备命令的字节数组。 我有一个方法使用相同的过程(即使用一个结构,然后将其串行化到一个字节数组,并将字节数组传递给写函数)。

有更好的选择吗?


如果您可以使用不安全的代码,则可以使用“固定”关键字将字节数组转换为指向结构的指针。


如果您自己调用本机dll,则可以定义您的DllImport-s,以便它们直接返回并接受COMMAND_GET_ADC - 只要您具有正确表示的结构。 框架本身应该照顾它。

如果你必须使用使用提供给你的方法的字节数组 - 那么我不知道,我从来没有这样的约束。 我一直试图用本地dll的相同方式来表示我的互操作性数据,但我不记得我有过这方面的重大问题。

编辑:

[StructLayout(LayoutKind.Explicit)]
public struct COMMAND_GET
{
    [FieldOffset(0)]
    public byte CommandID;
    [FieldOffset(1)]
    public byte PacketID;
    [FieldOffset(2)]
    public byte GetID;
    [FieldOffset(3)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
    public byte[] RFU;
    [FieldOffset(6)]
    public ADC_Data Adc_data;
    [FieldOffset(6)]
    public SomeOther_Data other_data;
    [FieldOffset(6)]
    ....
}


[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct ADC_Data
{
    public short Supply;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
    public short[] Current;
}

基本上你有FieldOffset(6)你在cmd_get_t中创建类似data union的联合

链接地址: http://www.djcxy.com/p/48991.html

上一篇: How do I convert a C# byte array into structured data?

下一篇: C++: Tool to reduce compile