IntPtr的算术 [英] IntPtr arithmetics

查看:134
本文介绍了IntPtr的算术的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I tried to allocate an array of structs in this way:

struct T {
    int a; int b;
}

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

我想获得分配的数据绑定一个struct的每个元素数组分配
与AllocHGlobal ......像这样

I'd like to access to allocated data "binding" a struct to each element in array allocated with AllocHGlobal... something like this

T v;
v = (T)Marshal.PtrToStructure(data+1, typeof(T));

但我没有找到任何方便的方式... 为什么IntPtr的缺乏算术的?我怎样才能在一个安全的方式解决此?

but i don't find any convenient way... why IntPtr lack of arithmetics? How can I workaround this in a "safe" way?

有人可以证实,PtrToStructure功能将数据复制到结构变量?换句话说,对矫正的结构反映在结构数组数据的修改,还是不?

Someone could confirm that PtrToStructure function copy data into the struct variable? In other words, modifing the struct reflect modifications in the structure array data, or not?

肯定地说,我想使用结构由一个IntPtr所指的数据进行操作,而不需要每次都复制数据,避免不安全的代码。

Definitely, I want to operate on data pointed by an IntPtr using struct, without copying data each time, avoiding unsafe code.

感谢大家!

推荐答案

您有四个选项,我可以认为,二只使用安全的代码,以及两个使用不安全的代码。该不安全的选项可能是显著更快

You have four options that I can think of, two using only "safe" code, and two using unsafe code. The unsafe options are likely to be significantly faster.


  • 分配您的阵列中的管理内存,并宣布你的P / Invoke功能采取的阵列。例如,而不是:

  • Allocate your array in managed memory, and declare your P/Invoke function to take the array. i.e., instead of:

[DllImport(...)]
static extern bool Foo(int count, IntPtr arrayPtr);



使其

make it

[DllImport(...)]
static extern bool Foo(int count, NativeType[] array);



(我使用本地类型为您结构名称,而不是 T ,因为 T 在一个通用的上下文中经常被使用。)

(I've used NativeType for your struct name instead of T, since T is often used in a generic context.)

这种方法的问题是,我的理解是,在本地类型[] 阵列将被两次每次调用封送到。它将从托管存储于托管
内存调用前被复制,并从非托管内存管理的内存之后复制。它可以改善,不过,如果将只读取或写入到阵列。在这种情况下,装饰与在tarray 参数的 [IN] (只读)或 [OUT] (只写)属性。这将允许运行跳过的复制步骤之一。

The problem with this approach is that, as I understand it, the NativeType[] array will be marshaled twice for every call to Foo. It will be copied from managed memory to unmanaged memory before the call, and copied from unmanaged memory to managed memory afterward. It can be improved, though, if Foo will only read from or write to the array. In this case, decorate the tarray parameter with an [In] (read only) or [Out] (write only) attribute. This allows the runtime to skip one of the copying steps.

由于你现在做的,在分配非托管内存阵列,并用一串电话到 Marshal.PtrToStructure Marshal.StructureToPtr 。这可能会比第一个选项执行更糟糕,因为你仍然需要复制的数组的元素来回,你正在做的步骤,让你有更多的开销。在另一方面,如果你有数组中的很多元素,但你只获得少数人在电话之间,那么这可能有更好的表现。您可能需要几个小助手功能,像这样:

As you're doing now, allocate the array in unmanaged memory, and use a bunch of calls to Marshal.PtrToStructure and Marshal.StructureToPtr. This will likely perform even worse than the first option, as you still need to copy elements of the array back and forth, and you're doing it in steps, so you have more overhead. On the other hand, if you have many elements in the array, but you only access a small number of them in between calls to Foo, then this may perform better. You might want a couple of little helper functions, like so:

static T ReadFromArray<T>(IntPtr arrayPtr, int index){
    // below, if you **know** you'll be on a 32-bit platform,
    // you can change ToInt64() to ToInt32().
    return (T)Marshal.PtrToStructure((IntPtr)(arrayPtr.ToInt64() +
        index * Marshal.SizeOf(typeof(T)));
}
// you might change `T value` below to `ref T value` to avoid one more copy
static void WriteToArray<T>(IntPtr arrayPtr, int index, T value){
    // below, if you **know** you'll be on a 32-bit platform,
    // you can change ToInt64() to ToInt32().
    Marshal.StructureToPtr(value, (IntPtr)(arrayPtr.ToInt64() +
        index * Marshal.SizeOf(typeof(T)), false);
}



  • 分配您的阵列中的非托管内存和使用指针来访问元素。这意味着所有使用该阵列中的代码必须是不安全块中。

IntPtr arrayPtr = Marhsal.AllocHGlobal(count * sizeof(typeof(NativeType)));
unsafe{
    NativeType* ptr = (NativeType*)arrayPtr.ToPointer();


ptr[0].Member1 = foo;
ptr[1].Member2 = bar;
/* and so on */



}
美孚(计数,arrayPtr);


  • 分配你的管理存储阵列,而当你需要调用本地子程序针它

  • Allocate your array in managed memory, and pin it when you need to call the native routine:

    NativeType[] array = new NativeType[count];
    array[0].Member1 = foo;
    array[1].Member2 = bar;
    /* and so on */
    
    
    unsafe{
        fixed(NativeType* ptr = array)
            Foo(count, (IntPtr)ptr);
            // or just Foo(count, ptr), if Foo is declare as such:
            //     static unsafe bool Foo(int count, NativeType* arrayPtr);
    }
    


  • 这最后一个选项是大概是干净的,如果你能使用不安全的代码和关心性能,因为你唯一的不安全的代码是你调用本机程序。如果性能是不是一个问题(也许如果数组的大小比较小),或者如果您不能使用不安全的代码(也许你没有完全信任),那么第一个选项可能是干净的,但是,正如我所提到的,如果你会调用之间访问与天然常规元件的数目是元件的数量的阵列内一小部分,则该第二个选择是更快

    This last option is probably the cleanest if you can use unsafe code and are concerned about performance, because your only unsafe code is where you call the native routine. If performance isn't an issue (perhaps if the size of the array is relatively small), or if you can't use unsafe code (perhaps you don't have full trust), then the first option is likely cleanest, although, as I mentioned, if the number of elements you'll access in between calls to the native routine are a small percentage of the number of elements within the array, then the second option is faster.

    在不安全的操作假定您的结构是的 blittable 。如果没有,那么安全的程序是你唯一的选择。

    The unsafe operations assume that your struct is blittable. If not, then the safe routines are your only option.

    这篇关于IntPtr的算术的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆