编组从.NET到C ++的结构数组:什么时候进行复制?

时间:2011-12-16 03:23:22

标签: c# .net performance pinvoke marshalling

考虑像System.Drawing.Point这样的结构 - 一个使用LayoutKind.Sequential并且只包含原始成员的结构。我有一个这样结构的C#数组。

我通过P / Invoke将它传递给(非托管)C ++函数。在C ++方面,有一个相应的结构定义(例如struct Point { int x, y; };)。该函数采用Point* arg。

我的问题是,在什么情况下CLR会复制数据,在什么情况下它会固定数据?变量包括:

  • 数组类型:一维或矩形
  • C#函数定义 - 使用Point*Point[] / Point[,]
  • 使用fixed(Point* pointer = array)或不使用

我想避免复制,因为它很慢。

2 个答案:

答案 0 :(得分:2)

我对固定没有多少经验,但是,根据我对MSDN的阅读,你的结构应该固定而不是复制。相关参考文献:

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

      

    格式化的blittable类在托管和非托管内存中都有固定的布局(格式化)和公共数据表示。当这些类型需要编组时,指向堆中对象的指针将直接传递给被调用者。

    你的Point结构在#3中作为例子给出,因此它有资格作为blittable类型。

    我注意到固定对象here会产生一些开销,但那是fixed byte[],这可能与您的Point[]不同。

答案 1 :(得分:0)

结构由值引用,类通过引用引用。

这意味着你总是有一个结构,并且你做了一个赋值,它的值被复制了,就像你使用int a = b; a具有b的值而不是点b所以如果你改变a的值,b将不会被更新。

如果你有一个数组,在内部它存储一个默认值向量,类的指针和结构的结构的默认值。请注意,如果struct包含一个作为引用类型(类)的成员,则存储设置为null的指针。

让你有

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

由于Point是打印值

时的结构(值类型)
p: {1, 1}
pa[0]: {0, 1}
pa[1-9]: {0, 0}

对于C ++,您可以使用foo(Point * pa)或foo(Point [] pa)获得相同的结果;在C#中使用单维数组中的foo(Point [] pa)。对于C ++中的矩形foo(Point ** pa)和C#中的foo(Point [] [])