将C#原始缓冲区重新解释为可蓝变的结构

时间:2019-05-26 21:49:03

标签: c# pointers unsafe reinterpret-cast stackalloc

我正在寻找一种方法来将任意不安全的内存区域重新解释为C#中的可漂白结构。到目前为止,这是我无法写的尝试:

[StructLayout(LayoutKind.Explicit, Size = sizeof(int))]
struct Foo
{
    [FieldOffset(0)]
    public int X;
}

public static unsafe void Main()
{
    // Allocate the buffer
    byte* buffer = stackalloc byte[sizeof(Foo)];

    // A tentative of reinterpreting the buffer as the struct
    Foo foo1 = Unsafe.AsRef<Foo>(buffer);

    // Another tentative to reinterpret as the struct
    Foo foo2 = *(Foo*) buffer;

    // Get back the address of the struct
    void* p1 = &foo1;
    void* p2 = &foo2;

    Console.WriteLine(new IntPtr(buffer).ToString("X"));
    Console.WriteLine(new IntPtr(p1).ToString("X"));
    Console.WriteLine(new IntPtr(p2).ToString("X"));
}

尽管如此,打印的内存地址都是不同的(我希望打印相同的地址)。第一次尝试使用Microsoft提供的Unsafe.AsRef<T>(..),其中方法说明为:

  

将给定位置重新解释为对类型T的引用。

我不确定为什么此处的重新解释不正确。

有什么建议吗?

1 个答案:

答案 0 :(得分:2)

重新解释按预期进行,地址不同是因为这两行在两个新变量中创建了独立的数据副本:

Foo foo1 = Unsafe.AsRef<Foo>(buffer);
// ...
Foo foo2 = *(Foo*) buffer;

为避免复制,您可以将变量声明为ref局部变量(从C#7开始)或指针:

byte* buffer = ...

// Option 1, pointers only
Foo* foo1 = (Foo*)buffer;
foo1->X = 123;

// Option 2, ref local cast from pointer    
ref Foo foo2 = ref *(Foo*)buffer;
foo2.X = 456;

// Option 3, ref local with Unsafe.AsRef
// Unlike option 2 this also allows reinterpreting non-blittable types,
// but in most cases that's probably undesirable
ref Foo foo3 = ref Unsafe.AsRef<Foo>(buffer);
foo3.X = 789;
相关问题