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

vld*_*jcc 6 c# pointers cil unmanaged fixed

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

int[] array = new int[3];
...
fixed (int* ptr = array)
{
    //some code
}
Run Code Online (Sandbox Code Playgroud)

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

.locals init ([0] int32[] 'array',
       [1] int32& pinned ptr)
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*eve 4

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

\n\n

第334页

\n\n
\n

"1.1.5.2 托管指针(& 类型)

\n\n

1.2托管指针 (&) 可以指向局部变量、方法参数、对象的字段、值类型的字段、数组的元素、静态字段或其中的地址将存储刚刚超过数组末尾的元素(用于托管数组中的指针索引)。托管指针\n不能为空。(即使它们不指向托管内存,也应将它们报告给垃圾收集器)”

\n
\n\n

第 149 页

\n\n
\n

7.1.2 固定

\n\n

固定的签名编码应仅出现在描述局部变量的签名中 (\xc2\xa715.4.1.3)。当具有固定局部变量的方法正在执行时,VES 不应重新定位局部引用的对象。也就是说,如果 CLI 的实现使用移动对象的垃圾收集器,则收集器不应移动由活动固定局部变量引用的对象。\n [基本原理:如果使用非托管指针取消引用托管对象,则这些对象应被固定。例如,当将托管对象传递给设计用于操作非托管数据的方法时,就会发生这种情况。结束理由]

\n
\n\n

我同意 Hans 的观点,认为 msil 语言设计选择背后的合理性。

\n\n
\n\n

这两件事是不同的:

\n\n
int[] arry = new int[5];\n\nfixed (int* ptr = arry)\n{\n  ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
int* ptr = stackalloc int[5];\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您查看为第二个创建的 IL,您将看到以下内容(我认为这正是您所期望的):

\n\n
.locals init ([0] int32* ptr)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n