unsafe static void Main(string[] args)
{
int i=6;
int* j = &i; //Allowed
int* k = j; //Allowed
fixed(int* q = &i) //Allowed
{
}
fixed(int* q = j) //Cannot declare pointer to non unmanaged type int*
{
}
}
我对第二个固定块所做的与我对第一个固定块的处理几乎相同。我将变量I的地址分配给指针q。允许直接分配地址,而在另一个指针中获取地址并在分配中使用该指针将失败。然而,在固定的上下文之外,同样的步骤也起了作用。。怎么回事?!
fixed
语句用于固定托管变量,这样垃圾收集器就不会移动它。
在正常操作中,垃圾收集器可以自由移动对象。这对指针来说将是一个问题,因为如果垃圾收集器移动了您有指针指向的对象,则该指针将不再有效。fixed
提供了一个解决方案,让您pin变量,告诉垃圾收集器指向对象的指针可能存在,并且在代码块期间不能移动它们。
C#编译器只允许您在固定语句中为托管变量分配指针。
堆栈上分配的变量(值类型)不受垃圾收集器的约束,也不会在内存中移动,因此fixed
对于此类变量来说既不必要也不正确。这就是为什么您的第二个(实际上也是第一个)fixed
语句会产生错误的原因。
您使用的C#版本是什么?第一个fixed
语句也不适合我编译(You cannot use the fixed statement to take the address of an already fixed expression
)。
修复非托管指针没有意义。它已经被修复了,GC永远不能碰它。
例如,当您将i
设置为类的成员字段时,这种情况会发生变化。突然间,它不再是方法的作用域,并且可以被GC(及其计数对象)移动。在这种情况下,必须使用fixed
语句。
编译器不允许您获取指向未修复的托管变量的指针,也不允许您修复非托管或固定变量。
同样,如果您将指针指向数组的开头,例如生成int[] i
并获取&i[0]
,则需要再次对其进行修复,因为它不再保证是本地作用域的。如果您确实需要一个本地作用域的非托管数组,您可以使用stackalloc
关键字,但同样,这基本上意味着您将脱离托管.NET.的相对安全性