9

Consider a struct like System.Drawing.Point - one with LayoutKind.Sequential and containing only primitive members. I have a C# array of such structs.

I'm passing it to an (unmanaged) C++ function via P/Invoke. On the C++ side there's a corresponding definition of the struct (e.g. struct Point { int x, y; };). The function takes a Point* arg.

My question is, in what cases does the CLR copy the data and in what cases does it just pin it? Variables include:

  • Array type: one-dimensional or rectangular
  • C# definition of the function - using Point* or Point[] / Point[,]
  • using fixed(Point* pointer = array) or not

I want to avoid the copying because it's slow.

Stefan Monov
  • 11,332
  • 10
  • 63
  • 120
  • It isn't documented, simple arrays just get pinned. Use the debugger in case of doubt, type `*&array` to get the array address in C#. And compare to the pointer value you get in the native code. +8 in 32-bit mode. – Hans Passant Dec 20 '11 at 02:39

2 Answers2

2

I don't have much experience with pinning, but, according to my reading of MSDN, your structs should be pinned and not copied. Relevant refs:

  1. Marshalling data with PInvoke
  2. Copying and pinning
  3. Blittable and non-blittable types
  4. Default marshalling for value types

From #2:

Formatted blittable classes have fixed layout (formatted) and common data representation in both managed and unmanaged memory. When these types require marshaling, a pointer to the object in the heap is passed to the callee directly.

And your Point struct is given as an example in #3, so it qualifies as a blittable type.

I noticed some overhead to pinning objects here, but that was for a fixed byte[], which may be different to your Point[].

Community
  • 1
  • 1
ligos
  • 4,256
  • 2
  • 25
  • 34
0

Structs are referenced by value and Classes are referenced by reference.

It means always you have a struct and you make an assignment its values are copied, like when you use int a = b; a has the value of b and not point so b so if you change the value of a, b will not be updated.

If you have an array, internally it stores a vector of defaults, pointers for classes and the default value of structure for structs. Notice that if the struct contains a member which is a reference type (class) a pointer set to null is stored.

Supose you have

Point p = new Point(0, 1);
Point[] pa = new Point[10];
pa[0] = p;
++p.X;

Since Point is a struct (value type) when you print the values

p: {1, 1}
pa[0]: {0, 1}
pa[1-9]: {0, 0}

For C++ you can use foo(Point *pa) or foo(Point[] pa) for same results; in C# use foo(Point[] pa) in single dimension array. For a rectangular foo(Point **pa) in C++ and foo(Point[][]) in C#

Kyordhel
  • 157
  • 3
  • 13