将结构数组从 .NET 编组到 C++:何时进行复制?

发布于 2024-12-21 23:08:46 字数 466 浏览 2 评论 0原文

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

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

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

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

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

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.

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

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

发布评论

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

评论(2

晨曦慕雪 2024-12-28 23:08:46

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

  1. 使用 PInvoke 编组数据
  2. 复制并固定
  3. 可传送和不可传送类型
  4. 值类型的默认编组

来自#2:

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

并且您的 Point 结构在 #3 中作为示例给出,因此它符合 blittable 类型。

我注意到固定对象的一些开销 此处,但那是针对固定字节[],这可能与您的不同点[]

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[].

你另情深 2024-12-28 23:08:46

结构体按值引用,类按引用引用。

这意味着你总是有一个结构体,并且你进行赋值,它的值会被复制,就像你使用 int a = b; 时一样。 a 具有 b 的值,而不是指向 b,因此如果更改 a 的值,b 将不会更新。

如果你有一个数组,它在内部存储一个默认向量、类的指针和结构的结构默认值。请注意,如果结构包含引用类型(类)的成员,则会存储设置为 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[][])

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#

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