“固定的” C# 中的语句和 CIL 代码中的托管指针

发布于 2024-11-17 10:35:06 字数 502 浏览 5 评论 0原文

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

int[] array = new int[3];

// ...

fixed (int* ptr = array)
{
    // Some code
}

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

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

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

In unsafe code in C#, I assigned a pointer to the managed variable of an array type:

int[] array = new int[3];

// ...

fixed (int* ptr = array)
{
    // Some code
}

Then I looked at corresponding part of the IL code:

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

Since this is unsafe code, and int* ptr is declaration of unmanaged pointer (or I think so at the moment), why in the CIL code doesn't write int32* ptr, instead of int32& ptr?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

老旧海报 2024-11-24 10:35:06

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

第334页

“1.1.5.2 托管指针(类型 &)

1.2 托管指针(&)可以指向局部变量、方法参数、
对象的字段、值的字段
类型、数组元素、静态
字段,或元素所在的地址
刚刚过去数组的末尾就是
存储(对于指针索引到
托管数组)。
托管指针
不能为空。 (他们应
报告给垃圾收集器,
即使它们没有指向托管
内存)”

第 149

7.1.2 固定

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

我同意 Hans 的观点,即 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 个整数。

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

Page 334

"1.1.5.2 Managed pointers (type &)

1.2 Managed pointers (&) can point to a local variable, a method argument, a
field of an object, a field of a value
type, an element of an array, a static
field, or the address where an element
just past the end of an array would be
stored (for pointer indexes into
managed arrays).
Managed pointers
cannot be null. (They shall be
reported to the garbage collector,
even if they do not point to managed
memory)"

Page 149

7.1.2 pinned

The signature encoding for pinned shall appear only in signatures that describe local variables (§15.4.1.3). While a method with a pinned local variable is executing, the VES shall not relocate the object to which the local refers. That is, if the implementation of the CLI uses a garbage collector that moves objects, the collector shall not move objects that are referenced by an active pinned local variable.
[Rationale: If unmanaged pointers are used to dereference managed objects, these objects shall be pinned. This happens, for example, when a managed object is passed to a method designed to operate with unmanaged data. end rationale]

I agree with Hans as to the rational behind the msil language design choice.


These two things are different:

int[] arry = new int[5];

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

vs.

int* ptr = stackalloc int[5];

If you look at the IL created for the second one, you'll see this (which I think is what you're expecting):

.locals init ([0] int32* ptr)

In the first version (your version), you're pointing to an instance of System.Array (a managed type). In my version (using stackalloc) you're pointing to what I think you're expecting to point to... a block of memory large enough for 5 ints.

陈甜 2024-11-24 10:35:06

ILDASM 是由 Microsoft 的 C++ 程序员编写的。在一种语言中,指针和引用之间的差异非常大。底层的 C++ 引用也是一个指针,但保证永远不会为空。引用在语法上用 & 标识,指针用 * 标识。

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

ILDASM was written by a C++ programmer at Microsoft. A language where the difference between pointers and references are a big deal. A C++ reference under the hood is also a pointer, but one that's guaranteed to never be null. A reference is syntactically identified by &, a pointer is *.

Which is the case here; there is a difference between the pointer and the pointed-to value. The pointed-to value may be null, but the reference to the pointer is never null. The "array" variable is guaranteed to be present in the stack frame and its reference thus have a non-null value. Only its value might be null. Which happens when the array isn't initialized. This level of indirection made pointers unpopular and largely absent in the C# language. And CS101.

标点 2024-11-24 10:35:06

C#是一种托管编码语言,因此不会有任何指针。但是有一个包装类可以使用指针。也许正因为如此,您注意到两者之间存在一些差异。

C# is a managed coded language, so there will not be any pointers. But there is a wrapper class to use the pointers. Maybe because of that, you are noticing some difference in these two.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文