【问题标题】:I'd like to use union as C# with byte array我想将 union 用作带有字节数组的 C#
【发布时间】:2012-10-11 15:59:36
【问题描述】:

我对串行通信中的消息解析有所了解,有多种形式的数据包。但都是字节数组发送的。

所以我想使用联合来解析每条消息。 但效果不佳。 以下代码是我出错的示例代码

[StructLayout(LayoutKind.Explicit, Size=12)]
public struct UnionPacket
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
    public byte[] data;

    [FieldOffset(0)]
    public float Time;
    [FieldOffset(4)]
    public Int16 CoordX;
    [FieldOffset(6)]
    public Int16 CoordY;
    [FieldOffset(8)]
    public byte Red;
    [FieldOffset(9)]
    public byte Green;
    [FieldOffset(10)]
    public byte Blue;
    [FieldOffset(11)]
    public byte Alpha;
}

如果这是可能的,那会很高兴,但事实并非如此。此代码发生 TypeLoadException “...因为它包含偏移量 0 处的对象字段,该对象字段未正确对齐或被非对象字段重叠。”

所以我改变了一些这样的代码

[StructLayout(LayoutKind.Explicit, Size= 12)]
public struct UnionPacket
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
    [FieldOffset(0)]
    public byte[] data;

    //[FieldOffset(0)]
    //public float Time;
    [FieldOffset(4)]
    public Int16 CoordX;
    [FieldOffset(6)]
    public Int16 CoordY;
    [FieldOffset(8)]
    public byte Red;
    [FieldOffset(9)]
    public byte Green;
    [FieldOffset(10)]
    public byte Blue;
    [FieldOffset(11)]
    public byte Alpha;
}

为了测试,我只是禁用了偏移量为 0 的时间字段,这并没有发生异常。但是,如果我更改其他字段,它不会更改字节数组。我认为字节数组的实际内存位置是在其他堆中分配的,所以不能这样做。

有没有办法在 C# 中解决这个问题?只有 C++ 或 C 可以解决这个问题吗? 如果我将它与继承一起使用,有可能吗?

附:对不起我的英语不好

【问题讨论】:

    标签: c# union packets


    【解决方案1】:

    我不能 100% 确定您要做什么,但是:

    第一种方法,如果将数组与固定/不安全关键字一起使用,则可以将数组存储在结构内。我不知道这对你来说是否可行。所以有这样的代码应该可以工作:

    [StructLayout(LayoutKind.Explicit, Size = 12)]
    public unsafe struct UnionPacket
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        [FieldOffset(0)]
        public fixed byte data[12];
    
        [FieldOffset(0)]
        public float Time;
        [FieldOffset(4)]
        public Int16 CoordX;
        [FieldOffset(6)]
        public Int16 CoordY;
        [FieldOffset(8)]
        public byte Red;
        [FieldOffset(9)]
        public byte Green;
        [FieldOffset(10)]
        public byte Blue;
        [FieldOffset(11)]
        public byte Alpha;
    }
    

    当然,那么你必须在 VS 中启用不安全的代码块并用它来包装你的结构:

    unsafe
    {
        var u = new UnionPacket();
        for (byte i = 0; i < 12; i++)
        {
             u.data[i] = i;
        }
        Console.WriteLine(u.Time);
        Console.WriteLine(u.CoordX);
        Console.WriteLine(u.CoordY);        
        Console.WriteLine(u.Red);
        Console.WriteLine(u.Green);
        Console.WriteLine(u.Blue);
        Console.WriteLine(u.Alpha);
    }
    

    其他方法是 - 只是忘记结构中的这个数组,并使用 Marshal.Copy 处理解析:

    [StructLayout(LayoutKind.Explicit, Size = 12)]
    public struct UnionPacket2
    {
        [FieldOffset(0)]
        public float Time;
        [FieldOffset(4)]
        public Int16 CoordX;
        [FieldOffset(6)]
        public Int16 CoordY;
        [FieldOffset(8)]
        public byte Red;
        [FieldOffset(9)]
        public byte Green;
        [FieldOffset(10)]
        public byte Blue;
        [FieldOffset(11)]
        public byte Alpha;
    }
    
    static void Main(string[] args)
    {
        var len = Marshal.SizeOf(typeof(UnionPacket2));
        var buffer = new byte[len];
        for (byte i = 0; i < len; i++)
        {
            buffer[i] = i;
        }
    
        var ptr = Marshal.AllocHGlobal(len);
        Marshal.Copy(buffer, 0, ptr, len);
        var u = (UnionPacket2)Marshal.PtrToStructure(ptr, typeof(UnionPacket2));
        Marshal.FreeHGlobal(ptr);
        Console.WriteLine(u.Time);
        Console.WriteLine(u.CoordX);
        Console.WriteLine(u.CoordY);
        Console.WriteLine(u.Red);
        Console.WriteLine(u.Green);
        Console.WriteLine(u.Blue);
        Console.WriteLine(u.Alpha);
    }
    

    【讨论】:

    • 谢谢,我使用了第二种方法,因为使用固定数组很难替换数据,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    相关资源
    最近更新 更多