修复了带有锯齿状数组的语句

发布于 2024-09-29 17:29:35 字数 611 浏览 6 评论 0原文

我有锯齿状数组,需要将其传递给外部方法。

[DllImport(...)]
private static extern int NativeMethod(IntPtr[] ptrArray);

...

fixed (ulong* ptr = array[0])
{
    for (int i = 0; i < array.Length; i++)
    {
        fixed (ulong* p = &array[i][0])
        {
            ptrArray[i] = new IntPtr(p);
        }
    }

    NativeMethod(ptrArray);
}

问题是 ptr 未使用并由于编译而被删除。比根据它的固定语句也被删除。因此,GC 会移动数组,从而使 ptrArray 元素变得无效。

将锯齿状数组作为单维指针数组传递给本机方法的最佳方法是什么?

更新:

以下是 NativeMethod 的 C++ 代码:

NativeClass::NativeMethod(const int* array)

I have jagged array which I need to pass to external method.

[DllImport(...)]
private static extern int NativeMethod(IntPtr[] ptrArray);

...

fixed (ulong* ptr = array[0])
{
    for (int i = 0; i < array.Length; i++)
    {
        fixed (ulong* p = &array[i][0])
        {
            ptrArray[i] = new IntPtr(p);
        }
    }

    NativeMethod(ptrArray);
}

The problem is that ptr is unused and is removed due compilation. Than fixed statement according to it is removed too. So array be moved by GC in that way that ptrArray elements become invalid.

What is the best way for passing jagged arrays as single-dimensional arrays of pointers to native methods?

Update:

Here is the C++ code for NativeMethod:

NativeClass::NativeMethod(const int* array)

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

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

发布评论

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

评论(2

傲影 2024-10-06 17:29:35

您的问题在于您需要修复数组,因为这是您正在使用的数组。您可以固定数组,以便 GC 不会收集它:

 GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);

更新

正如您所正确指出的,数组内的每个数组也需要固定。

Your problem is with the fact that you need array to be fixed since that is the one you are using. You can pin the array so that GC does not collect it:

 GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);

UPDATE

As you have correctly pointed out, each array inside the array needs pinning as well.

樱娆 2024-10-06 17:29:35

我已经能够通过外部 Pinvoke 方法将 C# 锯齿状数组传递给 C++,而无需使用不安全的 C# 代码,如下面的代码示例所示。但我仍然担心非调试模式下的 GC 会导致不良的副作用。这是一段测试代码(在调试模式下工作):

[Test, Ignore]
public void Test_JaggedArrayPInvoke()
{
    var jaggedArray = new int[3][];
    jaggedArray[0] = new int[1] { 9 };
    jaggedArray[1] = new int[4] { 1, 2, 3, 8 };
    jaggedArray[2] = new int[2] { 1, 2 };

    //GCHandle mainHandle = GCHandle.Alloc(jaggedArray, GCHandleType.Pinned);   //This does not work

    var pinnedHandles = new GCHandle[3];                    
    var jaggedArrayPtrs = new IntPtr[3];
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i] = GCHandle.Alloc(jaggedArray[i], GCHandleType.Pinned);
        jaggedArrayPtrs[i] = pinnedHandles[i].AddrOfPinnedObject();
    }

    var result = JaggedArrayPInvoke_TEST(jaggedArrayPtrs);

    Console.WriteLine(result);  //returns 8 as it should.

    //mainHandle.Free();
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i].Free();
    }
}

//The C++ test method:

extern "C" __declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray);
__declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray) 
{ 
   return jaggedArray[1][3];
}

如果我取消注释 mainHandle 部分,我会得到一个参数异常“对象包含非原始或不可直接传送的数据”。 那么是否有可能固定 jaggedArray 并且真的需要它吗?(我隐约记得,如果不再使用,释放模式下的 GC 可能会重新收集方法中已经存在的内存。)我认为尽管如此相反,从 GC 的角度来看,将 jaggedArray 转换为类字段变量会使其安全。

I have been able to pass a C# jagged array to C++ via an external Pinvoke method without using unsafe C# code as in the code sample below. But I still have my concerns regarding the GC in non-debug mode causing side undesirable side-effect. Here's the piece of test code (that works in debug mode):

[Test, Ignore]
public void Test_JaggedArrayPInvoke()
{
    var jaggedArray = new int[3][];
    jaggedArray[0] = new int[1] { 9 };
    jaggedArray[1] = new int[4] { 1, 2, 3, 8 };
    jaggedArray[2] = new int[2] { 1, 2 };

    //GCHandle mainHandle = GCHandle.Alloc(jaggedArray, GCHandleType.Pinned);   //This does not work

    var pinnedHandles = new GCHandle[3];                    
    var jaggedArrayPtrs = new IntPtr[3];
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i] = GCHandle.Alloc(jaggedArray[i], GCHandleType.Pinned);
        jaggedArrayPtrs[i] = pinnedHandles[i].AddrOfPinnedObject();
    }

    var result = JaggedArrayPInvoke_TEST(jaggedArrayPtrs);

    Console.WriteLine(result);  //returns 8 as it should.

    //mainHandle.Free();
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i].Free();
    }
}

//The C++ test method:

extern "C" __declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray);
__declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray) 
{ 
   return jaggedArray[1][3];
}

If I was to uncomment the mainHandle part, I get an argument exception "Object contains non-primitive or non-blittable data". So is it possible to pin the jaggedArray and is it really needed? (I vaguely recall that GC in release mode may recollect memory already within methods if it is not used any longer.) I think though that turning the jaggedArray into a class field variable instead would make it safe from a GC perspective.

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