C# 获取指向字节数组指针的不安全方法

C# 获取指向字节数组指针的不安全方法,c#,pointers,unsafe,C#,Pointers,Unsafe,这种行为在C语言中是否有效# 这段代码可以很好地编译,但是会导致运行时问题。这段代码实际上是从堆中偷运出一个指向未固定对象的指针。移动MyClass类型的下一个GC也将移动数据引用,并且以前从getData返回的任何值现在都将指向不正确的位置 var obj = new MyClass(); unsafe byte* pValue = obj.getData(); // Assuming no GC has happened (bad assumption) then this works fi

这种行为在C语言中是否有效#


这段代码可以很好地编译,但是会导致运行时问题。这段代码实际上是从堆中偷运出一个指向未固定对象的指针。移动
MyClass
类型的下一个GC也将移动
数据
引用,并且以前从
getData
返回的任何值现在都将指向不正确的位置

var obj = new MyClass();
unsafe byte* pValue = obj.getData();
// Assuming no GC has happened (bad assumption) then this works fine
*pValue = 42;

// Assume a GC has now happened and `obj` moved around in the heap.  The 
// following code is now over writing memory it simply doesn't own
*pValue = 42;

最后一行是否导致应用程序崩溃,在另一种类型中覆盖一个
字符串
值,或者只是将一个值插入一个未初始化的数组,然后在其他地方把一个数学问题搞糟?你不知道。最好的结果是代码很快崩溃,但很可能它会做一些更微妙和邪恶的事情

此代码将不起作用(它将编译,但在运行时会导致问题)。一旦区域结束,数据将不再固定。

否,一旦您离开
固定的
块,
结果的值将不再有效(如果GC未运行,它可能同时有效)


执行此类操作的正确方法是在非托管内存中引用通过C代码访问的
字节[]
,或者将托管数组复制到非托管内存中。

如果要关闭安全系统,则您有责任确保程序的内存安全。一旦您这样做,您就需要在没有安全系统帮助的情况下安全地完成所有工作。这就是“不安全”的意思

正如C#规范明确指出的那样:

可移动变量的地址只能使用固定语句获得,并且该地址仅在该固定语句的持续时间内保持有效

您正在获取一个可移动变量的地址,然后在fixed语句的持续时间之后使用它,因此该地址不再有效。因此,你被明确要求不要做你正在做的事情


在对必须遵循的规则有透彻深入的理解之前,不应该编写任何不安全的代码。从阅读本规范第18章开始。

您可以使用
Marshal.StructureToPtr()
方法,而不是不安全的magic:)

StructureToPtr
将结构的内容复制到预先分配的 ptr参数指向的内存块


编译它并查看。这永远是最好的发现方式,在这里问没有意义…你为什么要这样做?请不要试图在C中做C@循环:编译它只会告诉您代码在语法上是否有效,而不会告诉您代码在语义上是否有效。在这种情况下,即使运行代码也不一定能让您发现代码有缺陷。您的意思是说“fixeb block”而不是“unsafe block”?@JaredPar-不,fixed和unsafe是两个不同的关键字。当然可以修复不安全变量。@Ramhound是的,但不安全块不会以任何方式保护值。
对象可以在GC堆中自由移动,即使它当前处于不安全的块中。只有
fixed
块/引用会阻止堆内的移动。Jared是正确的。当控件离开固定块时,地址无效,而不是当控件离开不安全块时。参见C#规范的第18章。@JaredPar:是的,那是我的大脑放屁,意思是修复,写了不安全>你错了。您可以使用GCHandle结构,方法是使用pinted标志将对象固定到其内存地址,直到调用handle.Free()为止。@thefiloe:我知道这一点。这有什么关系?你认为我的哪句话是错的?
var obj = new MyClass();
unsafe byte* pValue = obj.getData();
// Assuming no GC has happened (bad assumption) then this works fine
*pValue = 42;

// Assume a GC has now happened and `obj` moved around in the heap.  The 
// following code is now over writing memory it simply doesn't own
*pValue = 42;