【问题标题】:C# parse bytes to struct sequentialC# 将字节解析为结构顺序
【发布时间】:2017-03-08 22:25:32
【问题描述】:

我尝试将字节数组解析为结构,但它不适用于 Sequential。 Sequential 结构中的值错误,但与 Explicit 结构一起使用是否正确?我需要顺序字节数组没有固定长度。 DwLength 字段是 Data 字段的大小。

价值观

  • 消息类型 128(顺序 128)
  • DwLength 20(连续 33554432)
  • 插槽 0(顺序 0)
  • 序列 0(序列 0)
  • 状态 2(连续 59)
  • 错误 0(顺序 143)
  • 链参数 0(顺序 128)

测试代码

var bytes = new byte[] { 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x3B, 0x8F, 0x80, 0x01, 0x80, 0x4F, 0x0C, 0xA0, 0x00, 0x00, 0x03, 0x06, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x68 };

var result1 = GetStruct<RdrToPcDataBlock1>(bytes);
var result2 = GetStruct<RdrToPcDataBlock2>(bytes);

struct RdrToPcDataBlock Sequential

[StructLayout(LayoutKind.Sequential)]
public struct RdrToPcDataBlock1
{
    public byte MessageType;
    public int DwLength;
    public byte Slot;
    public byte Seq;
    public byte Status;
    public byte Error;
    public byte ChainParameter;
    [MarshalAs(UnmanagedType.ByValArray)]
    public byte[] Data;
}

struct RdrToPcDataBlock 显式

[StructLayout(LayoutKind.Explicit)]
public struct RdrToPcDataBlock2
{
    [FieldOffset(0)]
    public byte MessageType;
    [FieldOffset(1)]
    public int DwLength;
    [FieldOffset(5)]
    public byte Slot;
    [FieldOffset(6)]
    public byte Seq;
    [FieldOffset(7)]
    public byte Status;
    [FieldOffset(8)]
    public byte Error;
    [FieldOffset(9)]
    public byte ChainParameter;
    [FieldOffset(10)]
    public byte Data;
}

GetStruct

public T GetStruct<T>(byte[] bytes)
{
    try
    {
        var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        var item = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        handle.Free();
        return item;
    }
    catch
    {
        return default(T);
    }
}

【问题讨论】:

  • “值错误” -- 请更具体。 “错”,以什么方式?你得到什么结果?你期望什么结果呢?请提供一个良好的minimal reproducible example 可靠地重现问题,并更准确地解释问题。另请注意,LayoutKind.Sequential 受打包规则的约束,因此未对齐的字段可能不会在您期望的地方结束。 (我现在没时间查,但我不相信即使你可以让LayoutKind.Sequential 工作,你也会得到你想要的结果,即最后一个数组对象充满了多余的数据。)
  • 您必须使用自定义编组器。否则你不能处理变长数组。这是一个示例:stackoverflow.com/a/38884095/103959

标签: c# arrays struct


【解决方案1】:

当您执行[StructLayout(LayoutKind.Sequential)] 时,这与执行[StructLayout(LayoutKind.Sequential, Pack=0)] 相同,它将使用默认打包来处理进程的位数(4 表示32 位,8 表示64 位)。要获得您想要的行为,您需要通过设置 [StructLayout(LayoutKind.Sequential, Pack=1)] 明确表示您不想要任何填充

更新:您仍然会遇到可变长度字节数组的问题。见comment by Jean-Bernard Pellerin

您必须使用自定义编组器。否则你不能处理变长数组。这是一个例子:https://stackoverflow.com/a/38884095/103959

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-01
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    • 2011-04-19
    • 1970-01-01
    相关资源
    最近更新 更多