【问题标题】:passing arrays from c++ to c# and back by value or by reference, which one is better and why?将数组从 c++ 传递到 c# 并按值或按引用返回,哪个更好,为什么?
【发布时间】:2017-01-07 09:40:12
【问题描述】:

我在this one 等线程中遵循了建议 关于如何将值数组从 c++ 传递到 c#。在@CodyGray 对我最近的问题here为什么我使用指针的评论之后,我尝试在没有指针和编组代码的情况下传递值,也遵循this
它也有效!我很困惑,正确/最好的方法是什么?为什么要在这里使用指针?

这里有一些代码:

考虑这个导出的 c++ 函数

extern "C" { __declspec(dllexport) void PointerTest(char ** text, float* fArray, int * iArray); }

这是我迄今为止在 c# 中所做的:

[System.Runtime.InteropServices.DllImport("myTest.dll")]
        private static extern void PointerTest(IntPtr text, IntPtr fArray, IntPtr iArray);

public static IntPtr NativeUtf8FromString(string managedString) {
            int len = Encoding.UTF8.GetByteCount(managedString);
            byte[] buffer = new byte[len + 1];
            Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0);
            IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length);
            Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length);
            return nativeUtf8;
            }

public void DoSomething(String text, float[] F, int[] I, int numFloats, int numInts){

            IntPtr sPtr = NativeUtf8FromString(text);
            IntPtr fPtr = Marshal.AllocHGlobal(numFloats*sizeof(float));
            IntPtr iPtr = Marshal.AllocHGlobal(numInts*sizeof(int));

            try
            {           
                Marshal.Copy(F, 0, fPtr, numFloats);
                Marshal.Copy(I, 0, iPtr, numInts);

                PointerTest(sPtr, fPtr, iPtr);
            }
            finally
            {
                Marshal.FreeHGlobal(sPtr);
                Marshal.FreeHGlobal(fPtr);
                Marshal.FreeHGlobal(iPtr);      
            }

        }

这在将值从 c# 传递到 c++ 时工作正常;但是,使用我发现的指针(可靠地)传回值的唯一方法是我的函数的返回值,这导致我将各种值填充到一个大数组中并返回(再次通过引用)。

现在考虑这段代码:

[System.Runtime.InteropServices.DllImport("myTest.dll")]
        private static extern void PointerTest([In, Out] String text, [In, Out] float[] fArray, [In, Out] int[] iArray);

public void DoSomething(String text, float[] F, int[] I){   
            PointerTest(text, F, I);
            }

据我所知,这也是同样的事情。另外,通过使用 [In, Out] 语义,我可以在调用 PointerTest 后轻松访问修改后的数组。

现在我在这里缺少什么?显然,对于像我这样的初学者来说,第二种方法更干净,更容易理解,并且在线的标准答案仍然是使用指针/第一种方法....这使我得出结论,第二种方法肯定有问题,但是我是从 msdn 那里得到的……

请帮助我理解这一点。提前致谢。

【问题讨论】:

  • c 和这个有关系吗?
  • C++ dll是如何构建的?也就是说,使用什么调用约定(stdcallcdecl 等)? C# 的默认值是stdcall,但是如果你使用cdecl 来处理C++ dll(即用/Gd 编译),你需要让你的DllImport 看起来像这样[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] .. 调用约定更改堆栈的清理方式(调用者/被调用者),这可能会影响您编组代码的方式
  • hm,感谢您清除...它是用 /Gd 构建的,我现在将其更改为 stdcall 并保留 c#。有趣的是,这个错误并没有导致错误.....

标签: c# c++ arrays pointers


【解决方案1】:

我对 C++/C# 互操作几乎一无所知,但根据 this documentation on improving interop performance(请参阅有关编组的部分),[In, Out] 与指针的选择应基于您的编组需求。 “通过将参数和字段声明为 IntPtr,”文档说,“您可以提高性能,尽管以牺牲易用性、类型安全性和可维护性为代价。”它还说“谨慎使用 [in] 和 [out] 属性以减少不必要的编组。”

我对文档的超级简要略读告诉我 [In, Out] 和指针都可以工作。似乎首先要考虑的是性能。对于您正在使用的数据,上述两种方法是否都足够高效?如果是这样,最好按照您的建议选择更清晰、更容易理解的选择。但不要相信我的话,看看吧! (就是文档。)

【讨论】:

  • aha...我可以看到如何传递地址而不是数据本身可以更快-atm 我正在处理相当少量的数据,所以我无法区分.. .. 谢谢你的链接,很多很好的信息!
猜你喜欢
  • 2014-12-20
  • 2020-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-02
相关资源
最近更新 更多