是否可以将固定字节数组转换为结构,以便在C#中实现双向更改?

时间:2012-10-21 21:39:07

标签: c# casting struct bytearray

我已经看到了一些将byte []复制到struct的方法,反之亦然。但是,我想知道是否可以将byte []指针强制转换为结构(就像你在C中那样)。

我希望能够将一个byte []转换为结构,对结构进行更改,并使更改自动出现在byte []中。

谢谢, 礼

3 个答案:

答案 0 :(得分:1)

你只是施放指针(有时你需要通过中间的void*):

struct Foo
{
    public int Bar;
}
static unsafe void Main()
{
    byte[] buffer = new byte[10];
    fixed (byte* untyped = buffer)
    {
        var typed = (Foo*)untyped;
        typed[0].Bar = 123;
    }
    // buffer has the changes
}

如果需要偏移到缓冲区,请使用byte* untyped = &buffer[offset]

如果你想要一个原始结构指针,那么:

fixed (byte* ptr = buffer)
{
    var typed = (Foo*)ptr;
    Foo* foo = &typed[0];
    foo->Bar = 123;
}

但请注意,您无法将Foo*传递给期望Fooref Foo的方法。

答案 1 :(得分:0)

我发现这种方法是最简单的实现我想要的..如果你定义结构使得byte []与元素重叠,那么副本在struct和byte []之间是有效透明的(假设是endian-ness是你所期望的;就我而言,它是)。

[StructLayout(LayoutKind.Explicit)]
    public unsafe struct ListEntry {
        [System.Runtime.InteropServices.FieldOffset(0)] public fixed byte raw[512];
        [System.Runtime.InteropServices.FieldOffset(0)] public byte version;
        [System.Runtime.InteropServices.FieldOffset(1)] public UInt16 magic;
        [System.Runtime.InteropServices.FieldOffset(3)] public UInt32 start_time;
        [System.Runtime.InteropServices.FieldOffset(7)] public UInt16 run_id;
        [System.Runtime.InteropServices.FieldOffset(9)] public UInt16 channels;
        [System.Runtime.InteropServices.FieldOffset(11)] public UInt16 sampling_rate;
        [System.Runtime.InteropServices.FieldOffset(13)] public UInt32 start_sector;
        [System.Runtime.InteropServices.FieldOffset(510)] public UInt16 checksum;
    }

答案 2 :(得分:0)

我建议你最好的选择,如果速度不是很关键,可能是将数据存储在byte[]中,并且有一个类,其中包含对byte[]的不可变引用并具有get / set方法访问数组的属性。属性获取/集合将始终反映并反映在数组的状态中,因为数组本身将保持对象的状态。不需要“不安全”的代码。

方法可能类似于:

public static class IntPack
{  // All methods ssume unchecked arithmetic
    public static Int16 FetchI16LE(this byte[] dat, int offset)
    {
        return (Int16)(dat[offset] + (dat[offset + 1] << 8));
    }
    public static Int32 FetchI32LE(this byte[] dat, int offset)
    {
        return dat[offset] + (dat[offset + 1] << 8) +
               (dat[offset + 2] << 16) + (dat[offset + 3] << 24);
    }
    public static void StuffI16LE(this byte[] dat, int offset, int value)
    {
        dat[offset] = (byte)(value); 
        dat[offset+1] = (byte)(value >> 8);
    }
    public static void StuffI32LE(this byte[] dat, int offset, int value)
    {
        dat[offset] = (byte)(value);
        dat[offset + 1] = (byte)(value >> 8);
        dat[offset + 2] = (byte)(value >> 16);
        dat[offset + 3] = (byte)(value >> 24);
    }
}

指示的方法假设小端排序。人们可以轻松地为big-endian编写相应的__BE方法。