C#中的fixed语句和IL代码中的托管指针

时间:2011-06-25 20:54:28

标签: c# pointers unmanaged cil fixed

在C#中的不安全代码中,我分配了指向数组类型的托管变量的指针:

int[] array = new int[3];
...
fixed (int* ptr = array)
{
    //some code
}

然后我查看了IL代码的相应部分:

.locals init ([0] int32[] 'array',
       [1] int32& pinned ptr)

我想知道,因为这是不安全的代码,int* ptr是非托管指针的声明(或者我现在这么认为),为什么在IL代码中不写int32* ptr,而是是int32& ptr

3 个答案:

答案 0 :(得分:3)

http://www.ecma-international.org/publications/standards/Ecma-335.htm

Page 334

  

“1.1.5.2管理指针(类型&)

     

1.2 托管指针(&)可以指向局部变量,方法参数,a   对象的字段,值的字段   type,数组元素,static   字段,或元素的地址   刚过阵列结束就可以了   存储(用于指针索引)   托管数组)。托管指针   不能为空。 (他们应该是   报告给垃圾收集者,   即使他们没有指出管理   存储器)“

Page 149

  

7.1.2固定

     

固定的签名编码只能出现在描述局部变量的签名中(第15.4.1.3节)。 当一个带有固定局部变量的方法正在执行时,VES不应该重定位本地引用的对象。也就是说,如果CLI的实现使用移动对象的垃圾收集器,那么收集器不得移动由活动的固定局部变量引用的对象。   [基本原理:如果使用非托管指针取消引用托管对象,则应固定这些对象。例如,当托管对象传递给设计用于处理非托管数据的方法时,就会发生这种情况。最终理由]

我同意汉斯关于msil语言设计选择背后的理性。


这两件事情有所不同:

int[] arry = new int[5];

fixed (int* ptr = arry)
{
  ...
}

VS

int* ptr = stackalloc int[5];

如果你看看为第二个创建的IL,你会看到这个(我认为这是你所期待的):

.locals init ([0] int32* ptr)

在第一个版本(您的版本)中,您指向System.Array(托管类型)的实例。在我的版本中(使用stackalloc)你指的是我认为你期望指向的东西......一块足够大的内存块,可以存储5个整数。

答案 1 :(得分:2)

Ildasm是由Microsoft的C ++程序员编写的。一种语言,指针和引用之间的区别是一个大问题。引擎盖下的C ++引用也是一个指针,但保证永远不会为null。引用在语法上由&标识,指针是*。

这里是这种情况,指针和指向值之间存在差异。指向的值可以为null,但对指针的引用永远不为null。保证“数组”变量存在于堆栈帧中,因此其引用具有非空值。只有它的可能为空。当数组未初始化时会发生这种情况。这种间接性使得指针不受欢迎,并且在C#语言中基本上不存在。和CS101。

答案 2 :(得分:-5)

c#是一种托管编码语言,因此不会有任何指针。但是有一个使用指针的包装类可能是因为你注意到这两个方面的一些区别。