Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fixed statement in C# and managed pointer in IL code

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?

like image 522
vldmrrdjcc Avatar asked Jun 25 '11 20:06

vldmrrdjcc


People also ask

What is a fixed statement?

The fixed statement prevents the garbage collector from relocating a moveable variable and declares a pointer to that variable: C# Copy.

Are C# arrays fixed size?

In C#, arrays can be declared as fixed-length or dynamic. A fixed-length array can store a predefined number of items. A dynamic array does not have a predefined size. The size of a dynamic array increases as you add new items to the array.


2 Answers

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.

like image 104
Steve Avatar answered Oct 04 '22 03:10

Steve


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.

like image 29
Hans Passant Avatar answered Oct 04 '22 04:10

Hans Passant