从结构分配的字节数组上的 C# 指针算法

本文关键字:指针 算法 数组 字节数 结构 分配 字节 | 更新日期: 2023-09-27 18:36:41

来自:

http://www.developerfusion.com/article/84519/mastering-structs-in-c/

建议将结构中的字节数组声明为单个字节,然后使用 FieldOffset 为数组分配内存。分配内存后,可以使用指针算法访问数组。

例:

[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 1300)]
public struct TGLProtocolBuffer
{
    [FieldOffset(0)]
    public byte StartByte;
    [FieldOffset(1)]
    public byte MessageNumber;
    [FieldOffset(2)]
    public UInt16 Command;
    [FieldOffset(4)]
    public UInt32 UnitID;
    [FieldOffset(8)]
    public UInt16 DataLength;
    [FieldOffset(10)]
    public byte Data;
};

我想使用 Array.Copy 在此内存上运行,但需要将结构中定义的数组转换为字节到 byte[]

如何将字节转换为字节[]?

从结构分配的字节数组上的 C# 指针算法

你可以在结构中创建一个字节数组,遍历整个事情。(这与C++工会相同)
使用它,您可以访问结构中的每个字节。

[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 1300)]
public struct TGLProtocolBuffer
{
    [FieldOffset(0)]
    public byte[] byteArray;   // <--
    [FieldOffset(0)]
    public byte StartByte;
    [FieldOffset(1)]
    public byte MessageNumber;
    [FieldOffset(2)]
    public UInt16 Command;
    [FieldOffset(4)]
    public UInt32 UnitID;
    [FieldOffset(8)]
    public UInt16 DataLength;
    [FieldOffset(10)]
    public byte Data;
};

如果仅Data字段需要此功能,则可以简单地将其声明为 byte[] 而不是 byte
或者,您可以同时使用两者:

    [FieldOffset(10)]
    public byte Data;
    [FieldOffset(10)]
    public byte[] DataArray;

您可能需要使用 定义数组大小

public byte[1290] DataArray;

[MarshalAs(UnmanagedType.U1, SizeConst=1290)]

你不能将一个字节"投射"到一个字节[],你可以用一个字节创建一个字节[]:

byte b = ...
byte[] ba = new byte[1];
ba[0] = b;

我立即意识到的唯一方法是在不安全的上下文中使用固定字节。这最终将创建一个指向byte*的指针。使用起来有点奇怪。

[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 1300)]
unsafe public struct TGLProtocolBuffer
{
    [FieldOffset(0)]
    public byte StartByte;
    [FieldOffset(1)]
    public byte MessageNumber;
    [FieldOffset(2)]
    public UInt16 Command;
    [FieldOffset(4)]
    public UInt32 UnitID;
    [FieldOffset(8)]
    public UInt16 DataLength;
    [FieldOffset(10)]
    public fixed byte Data[1290];
};

要从数据中获取实际的字节数组,您需要一个帮助程序方法。

unsafe static void GetBytesFromPointer(byte* data, byte[] output)
{
    for (int i = 0; i < output.Length; i++)
    {
        output[i] = data[i];
    }
}

然后你应该像这样称呼它。

var data = new byte[1290];
GetBytesFromPointer(tglProtocolBuffer.Data, data);

作为对此的补充,这里有一个测试封送处理的快速小方法。

unsafe public static void Main(string[] args)
{
    var data = new byte[1300];
    new Random().NextBytes(data);
    fixed(byte* dataFixed = data)
    {
        dataFixed[10] = 0; //add marker byte so we can spot that extracted data starts with a 0 byte
        var tglProtocolBuffer = (TGLProtocolBuffer) Marshal.PtrToStructure((IntPtr) dataFixed, typeof (TGLProtocolBuffer));
        var bytesFromStruct = new byte[1290];
        GetBytesFromPointer(tglProtocolBuffer.Data, bytesFromStruct);
        Debug.Assert(bytesFromStruct[0] == 0);
    }
}