【问题标题】:How to convert byte array to union struct by one operation?如何通过一次操作将字节数组转换为联合结构?
【发布时间】:2016-11-16 10:05:12
【问题描述】:

我在 C# 中声明了类似于 C++ 中的 union:

[StructLayout(LayoutKind.Explicit, Size = 5)]
public struct Marker
{
        [FieldOffset(0)] public byte label;
        [FieldOffset(1)] public int count;

        [FieldOffset(1)] private byte count_0;
        [FieldOffset(2)] private byte count_1;
        [FieldOffset(3)] private byte count_2;
        [FieldOffset(4)] private byte count_3;
}

我还有大小为 5 的 byte[] bytes。我需要将我的数组转换为 Marker 对象。我可以通过以下方式做到这一点:

var marker = new Marker 
{
    label = bytes[0],
    count = BitConverter.ToInt32(bytes, 1)
}

或者:

var marker = new Marker 
{
    label = bytes[0],
    count_0 = bytes[1],
    count_1 = bytes[2],
    count_2 = bytes[3],
    count_3 = bytes[4]
}

没关系,但我认为从性能角度来看,可以通过更优化的方式来做到这一点 - 只需将 marker 指向 bytes 的第一个字节。我试图找到这样的东西:

BitConverter.To<Marker>(bytes);

如何通过一次操作将字节数组转换为联合结构?

【问题讨论】:

    标签: c# struct type-conversion byte union


    【解决方案1】:

    这应该可以工作

        static void Main(string[] args)
        {
            //Creating test data
            List<byte> data = new List<byte>();
            data.Add(123);
            data.AddRange(BitConverter.GetBytes((int)123456));
    
            //Converting test data to Struct
            Marker m = StructFromBytes<Marker>(data.ToArray());
    
            //Check if it works
            Console.WriteLine(m.label); //Prints 123
            Console.WriteLine(m.count); //Prints 123456
        }
    
        private static T StructFromBytes<T>(byte[] bytes)
        {
            int structSize = Marshal.SizeOf(typeof(T));
            byte[] structBytes = new byte[structSize];
            Array.Copy(bytes, 0, structBytes, 0, structSize);
    
            GCHandle handle = GCHandle.Alloc(structBytes, GCHandleType.Pinned);
            T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
            handle.Free();
    
            return theStructure;
        }
    

    【讨论】:

    • 如果性能是您的问题,那将适得其反。固定数据并对其进行编组应该方式比仅分配值更耗时。
    • 他在问题中说他想要最佳性能。互操作不会是要走的路...
    • 我同意,这就是为什么我赞成你的回答。但是 OP 也希望以简单的方式做到这一点,使用 StructFromBytes&lt;Marker&gt;(bytes) 比为每个结构创建构造函数更容易。
    • 没错,如果你有很多不同的结构,你的方式足够灵活,可以处理所有这些。这取决于你的目标是什么。
    【解决方案2】:

    你可以创建一个构造函数:

    [StructLayout(LayoutKind.Explicit, Size = 5)]
    public struct Marker
    {
        [FieldOffset(0)] public byte label;
        [FieldOffset(1)] public int count;
    
        [FieldOffset(1)] private byte count_0;
        [FieldOffset(2)] private byte count_1;
        [FieldOffset(3)] private byte count_2;
        [FieldOffset(4)] private byte count_3;
    
        public Marker(byte[] bytes)
        {
           label = bytes[0];
           count_0 = bytes[1];
           count_1 = bytes[2];
           count_2 = bytes[3];
           count_3 = bytes[4];
        }
    }
    

    或运算符重载:

    [StructLayout(LayoutKind.Explicit, Size = 5)]
    public struct Marker
    {
        [FieldOffset(0)] public byte label;
        [FieldOffset(1)] public int count;
    
        [FieldOffset(1)] private byte count_0;
        [FieldOffset(2)] private byte count_1;
        [FieldOffset(3)] private byte count_2;
        [FieldOffset(4)] private byte count_3;
    
        public static explicit operator Marker(byte[] bytes)
        {
           Marker result = new Marker();
           result.label = bytes[0];
           result.count_0 = bytes[1];
           result.count_1 = bytes[2];
           result.count_2 = bytes[3];
           result.count_3 = bytes[4];
           return result;
        }
    }
    

    这两种解决方案都会让你的结构变得单行:

    Marker marker = new Marker(bytes);
    Marker marker = (Marker)bytes;
    

    【讨论】:

    • 这是一样的。对于每个result.count_'x' = bytes['y'],将使用一个 Int32 或 Int64 处理器命令。
    • 你为什么要关心?你对表现如此严格以至于对你很重要吗?如果要优化性能,请运行分析器。与担心 CPU 命令相比,这会更好地利用您的时间。
    • 我使用structFieldOffset 进行字节映射——当然这个问题是关于性能的。我不需要使用分析器我看到性能问题(在我的实际任务中这很关键),我正在努力寻找解决方案。我编辑了我的问题以便更清楚。
    • 到目前为止,通过修改系统设计可以实现最大的性能提升。当归结为 CPU 命令数量的微小变化会产生影响时,C# 是错误的语言。您必须使用汇编语言才能影响 CPU 命令级别的性能。
    • 不知道你也可以为你创建自己的演员 +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 2011-03-17
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多