c# - 将 C# 原始缓冲区重新解释为 blittable 结构
问题描述
我正在寻找一种方法来将任意不安全的内存区域重新解释为 C# 中的 blittable 结构。到目前为止,这是我可以写的一次失败的尝试:
[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"));
}
尽管如此,打印的内存地址都是不同的(我希望打印相同的地址)。第一次尝试使用Unsafe.AsRef<T>(..)
微软提供的方法,其中方法的描述说:
将给定位置重新解释为对 type 值的引用
T
。
我不确定为什么这里没有正确完成重新解释。
有什么建议吗?
解决方案
重新解释按预期工作,地址不同的原因是这两行在两个新变量中创建了独立的数据副本:
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;
推荐阅读
- regex - 从 std::regex_search 获取迭代器并在 string::replace 中使用它们
- c++ - 何时将 std::future 和 std::promise 与 std::thread 一起使用
- android - 如何在现有项目中创建和使用 Android 库
- python - 如何使用“With open()”读取网址?
- python - 重新启动 pygame/python 脚本
- javascript - Uno.Lottie WebAssembly 中未捕获的类型 JavaScript 错误
- precision - 具有某些运动方程的数值积分器的误差极低
- c - 达到最大字符限制时如何折叠输入?
- angular - 使用 Angular 和 Deno 在浏览器中的 CSS MIME 不匹配
- spring-boot - Spring Boot JWT token 基于角色的授权问题