从 C++ 到 C# 的 P/Invoking int[] 显示随机大数而不是原始数组成员

Posted

技术标签:

【中文标题】从 C++ 到 C# 的 P/Invoking int[] 显示随机大数而不是原始数组成员【英文标题】:P/Invoking int[] from c++ to C# shows random large numbers instead of original array members 【发布时间】:2019-05-17 03:53:49 【问题描述】:

我有以下 c++ 代码:

int nCount[5] = 0, 1, 2, 3, 4;    
return &nCount[0];

我在 C# P/Invoke 层收到此代码,代码如下:

[DllImport(@"/sharedlibrary.so",CallingConvention = CallingConvention.Cdecl)]                                
 public extern static IntPtr read_array_adapter();

效果很好。但是当我在下面运行 c# 代码时:

int[] result = new int[5];
Marshal.Copy(ptr, result, 0, 5); 

它用一些随机大数填充数组结果,如下所示:

int[]1663918692,1852139884,1970351988,1936417641,244554078

这与我在 C++ 中的原始数组无关,看起来像 0,1,2,3,4 知道Marshal.Copy 可能会做什么来填充这些结果吗?

【问题讨论】:

int nCount[5] = 0, 1, 2, 3, 4; return &nCount[0]; -- 如果nCount 是局部变量,这将不起作用。您应该指定声明该数组的位置,因为这比您想象的要多得多。 它是一个局部函数变量。我应该怎样才能获得真正的价值观? 好吧,让数组全局化。在 C++ 中返回局部变量的地址是未定义的行为。 见***.com/questions/6441218/… 您还需要指定该数组的意图。很难相信它只存在 5 个数字,0,1,2,3,4。心中必须有一个更大的计划。该计划将决定您要如何指定该数组的声明位置和方式。 【参考方案1】:

如果您希望内存在函数范围内存在,并且不想使用全局变量,那么您必须从堆栈以外的其他位置(局部变量)分配它。

您可以使用任何分配器,您可以使用 .NET 已经知道的分配器,或者如果您使用另一个特定于 C++ 或您的平台的分配器,那么您还必须提供另一个 P/Invokable 函数用于解除分配,如下所示:

C++

int* read_array_adapter()

    int nCount[5] = 0, 1, 2, 3, 4;    
    return AllocateAndCopy(...);


void free_array_adapter(int *) // or a generic pointer of course...

    Free(...);

C#

static void Main(string[] args)

    var ptr = read_array_adapter();
    var result = new int[5];
    Marshal.Copy(ptr, result, 0, 5);
    free_array_adapter(ptr);


[DllImport(@"/sharedlibrary.so",CallingConvention = CallingConvention.Cdecl)]                                
public extern static IntPtr read_array_adapter();

[DllImport(@"/sharedlibrary.so",CallingConvention = CallingConvention.Cdecl)]                                
public extern static void free_array_adapter(IntPtr ptr);

您也可以在 .NET 和 C/C++ 之间使用已知的分配器,但这取决于平台(Windows、linux 等):https://www.mono-project.com/docs/advanced/pinvoke/

这是一个使用 C 的 malloc/free duo 的示例实现:

int* read_array_adapter()

    int nCount[5] =  0, 1, 2, 3, 4 ;
    int* p = (int*)malloc(5 * 4);
    memcpy(p, nCount, 5 * 4);
    return p;


void free_array_adapter(void * ptr)

    free(ptr);

【讨论】:

什么是''allocateAndCopy? 任何你能想到的分配(+复制)功能。 Free 将是它的释放部分。 你能给我举个例子来说明这个分配和复制函数的样子吗?我有点迷路了。此外,我尝试通过引用传递 IntPtr,希望它能够在调用中幸存下来,但它仍然以错误的值结束:( 任何分配器/释放器都可以。我已经用 malloc/free 更新了我的答案。 非常感谢。您提供的示例刚刚修复了它。真的是一堆。但是有一个问题,这对于可变大小的字符串是否足够安全?

以上是关于从 C++ 到 C# 的 P/Invoking int[] 显示随机大数而不是原始数组成员的主要内容,如果未能解决你的问题,请参考以下文章

将浮点数组从 C++ 获取到 C#

从 C# 访问 C 全局变量 'errno'

通过引用从 c# 将 char** 传递给非托管 C++

如何使用 DLLImport 将字符串从 C# 传递到 C++(以及从 C++ 到 C#)?

将字符串从 C# 发送到 C++

从 C# 到 C++ 触发 COM 事件的正确方法是啥