C# 获取指向字节数组指针的不安全方法
这种行为在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
这段代码可以很好地编译,但是会导致运行时问题。这段代码实际上是从堆中偷运出一个指向未固定对象的指针。移动
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;