首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IntPtr算法

IntPtr算法
EN

Stack Overflow用户
提问于 2009-08-23 14:17:04
回答 5查看 5.2K关注 0票数 7

我试图以这种方式分配一个结构数组:

代码语言:javascript
复制
struct T {
    int a; int b;
}

data = Marshal.AllocHGlobal(count*Marshal.SizeOf(typeof(T));
...

我想访问分配的数据“绑定”一个结构到数组中的每个元素,用AllocHGlobal.像这样的东西

代码语言:javascript
复制
T v;
v = (T)Marshal.PtrToStructure(data+1, typeof(T));

但我找不到方便的方法..。为什么IntPtr缺少算术?我怎样才能以“安全”的方式解决这个问题呢?

有人可以确认PtrToStructure函数将数据复制到struct变量中吗?换句话说,修改结构反映了对结构数组数据的修改,还是没有?

当然,我希望使用struct对IntPtr所指向的数据进行操作,避免每次复制数据,避免不安全的代码。

谢谢大家!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-08-23 16:18:44

我可以想到四个选项,两个只使用“安全”代码,两个使用不安全代码。不安全的选择可能要快得多。

外汇局:

  • 在托管内存中分配数组,并声明您的P/Invoke函数以接受该数组。即:而不是: DllImport(.)静态外bool Foo(int计数,IntPtr arrayPtr); 搞定 DllImport(.)静态输出bool (int计数,NativeType[]数组); (我使用NativeType作为您的结构名称,而不是T,因为T经常用于泛型上下文中。) 这种方法的问题是,据我所知,NativeType[]数组将在每次调用Foo时被封送两次。它将在调用之前从托管内存复制到非托管内存,然后从非托管内存复制到托管内存。但是,如果Foo只从数组中读取或写入数组,则可以对其进行改进。在本例中,将tarray参数修饰为[In] (只读)或[Out] (只写)属性。这允许运行时跳过一个复制步骤。
  • 正如您现在所做的,在非托管内存中分配数组,并使用对Marshal.PtrToStructureMarshal.StructureToPtr的一系列调用。这可能会比第一个选项执行得更糟糕,因为您仍然需要来回复制数组的元素,并且正在分步骤进行,因此您有更多的开销。另一方面,如果数组中有许多元素,但在调用Foo期间只访问其中的一小部分元素,那么这可能会执行得更好。您可能需要一些小助手函数,如下所示: 静态T ReadFromArray(IntPtr arrayPtr,int索引){ //下面,如果您知道*您将在32位平台上,//您可以将ToInt64()更改为ToInt32()。返回(T)Marshal.PtrToStructure((IntPtr)(arrayPtr.ToInt64() + index *Marshal.SizeOf(typeof(T));} //您可能会将下面的T value更改为ref T value,以避免再次复制静态无效WriteToArray(IntPtr arrayPtr,int索引,T值){ //下面,如果您知道*您将在32位平台上,//您可以将ToInt64()更改为ToInt32()。Marshal.StructureToPtr(value,(IntPtr))(arrayPtr.ToInt64()+ index * Marshal.SizeOf(typeof(T)),false);}

不安全:

  • 在非托管内存中分配数组,并使用指针访问元素。这意味着使用数组的所有代码都必须在unsafe块中。 IntPtr arrayPtr = Marhsal.AllocHGlobal(count *sizeof(NativeType));不安全的{ NativeType* ptr = (NativeType*)arrayPtr.ToPointer();ptr.Member1 = foo;ptr1.Member2 = bar;/*等等*/ } Foo(count,arrayPtr);
  • 在托管内存中分配数组,并在需要调用本机例程时将其固定: NativeType[]数组=新的NativeTypecount;array.Member1 = foo;array1.Member2 = bar;/*等等*/不安全的{ Foo ( NativeType* ptr =数组) Foo(count,(IntPtr)ptr);/或仅仅Foo(count,ptr),如果Foo声明为: //静态不安全bool Foo(int count,NativeType* arrayPtr);

如果可以使用不安全代码并考虑性能,则最后一个选项可能是最干净的,因为您唯一的不安全代码是调用本机例程的位置。如果性能不是问题(可能是数组的大小相对较小),或者如果您不能使用不安全的代码(可能您没有完全信任),那么第一个选项可能是最干净的,尽管正如我前面提到的,如果您在调用本机例程之间访问的元素数量只占数组中元素数的一小部分,那么第二个选项就更快了。

注意:

不安全操作假定您的结构是闪电战。如果没有,那么安全的例程是你唯一的选择。

票数 11
EN

Stack Overflow用户

发布于 2009-08-23 14:45:54

“为什么IntPtr缺少算术?”

IntPtr只存储一个内存地址。它没有任何关于内存位置内容的信息。以这种方式,它类似于void*。要启用指针算法,您必须知道所指向对象的大小。

从根本上说,IntPtr主要用于托管上下文中作为一个不透明句柄(即,在托管代码中不直接取消引用,只需将其传递给非托管代码)。unsafe上下文提供您可以直接操作的指针。

票数 8
EN

Stack Overflow用户

发布于 2009-08-23 14:24:13

实际上,IntPtr类型没有自己的算术运算符。在C#中支持正确(不安全)指针算法,但是IntPtrMarshal类是为了更安全地使用指针而存在的。

我想你想要的东西如下:

代码语言:javascript
复制
int index = 1; // 2nd element of array
var v = (T)Marshal.PtrToStructure(new IntPtr(data.ToInt32() + 
    index * Marshal.SizeOf(typeof(T)), typeof(T));

另外,请注意,IntPtrintIntPtr之间没有隐式转换,因此没有运气。

通常,如果要使用指针执行任何稍微复杂的操作,最好选择不安全的代码。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1318682

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档