此行为在C#中有效
public class MyClass
{
private byte[] data;
public MyClass()
{
this.data = new byte[1024];
}
public unsafe byte* getData()
{
byte* result = null;
fixed (byte* dataPtr = data)
{
result = dataPtr;
}
return result;
}
}
答案 0 :(得分:17)
如果您要关闭安全系统,那么您有责任确保程序的内存安全。一旦你这样做,你需要安全地完成所有事情而不需要安全系统帮助你。这就是“不安全”的含义。
正如C#规范明确指出:
只能使用固定语句获取可移动变量的地址,并且该地址仅在该固定语句的持续时间内有效。
您正在获取可移动变量的地址,然后在fixed语句的持续时间之后使用它,因此该地址不再是有效。因此,您特别要求不能正确地执行您正在做的事情。
在深入了解必须遵循的规则之前,不应编写任何不安全的代码。首先阅读规范第18章的所有内容。
答案 1 :(得分:11)
这段代码编译得很好,但会导致运行时问题。代码基本上是走私指向堆中未固定对象的指针。移动MyClass
类型的下一个GC也会移动data
引用,而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;
最后一行是否导致应用程序崩溃,覆盖另一种类型的string
值,或者只是将值戳入未初始化的数组中,而只是搞砸了数学问题?你不知道。最好的结果是代码只是快速崩溃,但在所有可能的情况下,它会做一些更微妙和邪恶的事情。
答案 2 :(得分:2)
您可以使用Marshal.StructureToPtr()
方法代替不安全的魔法:)
StructureToPtr
将结构内容复制到预分配 ptr参数指向的内存块。
答案 3 :(得分:1)
此代码不起作用(它将编译但在运行时会导致问题)。 fixed区域结束后,数据将不再固定。
答案 4 :(得分:0)
不,一旦你离开fixed
块,result
的值就不再有效了(如果GC没有运行,它可能同时有效)。
执行此类操作的正确方法是在非托管内存中引用可通过C#代码访问的byte[]
,或将托管阵列复制到非托管内存中。