C# 将字节解析为结构顺序

Posted

技术标签:

【中文标题】C# 将字节解析为结构顺序【英文标题】:C# parse bytes to struct sequential 【发布时间】: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 工作,你也会得到你想要的结果,即最后一个数组对象充满了多余的数据。) 您必须使用自定义编组器。否则你不能处理变长数组。这是一个示例:***.com/a/38884095/103959 【参考方案1】:

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

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

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

【讨论】:

以上是关于C# 将字节解析为结构顺序的主要内容,如果未能解决你的问题,请参考以下文章

《C#零基础入门之百识百例》顺序结构 -- 梯形面积

数据结构:顺序表(实现方式及扩展等)

数据结构:顺序表(实现方式及扩展等)

为啥 fread 会弄乱我的字节顺序?

线性表的顺序存储结构

C#数据结构-二叉树-顺序存储结构