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

P/Invoking int[] from c++ to C# shows random large numbers instead of original array members

我有以下 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 可能会做什么来填充这些结果吗?

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

你可以使用任何分配器,你可以使用 .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);
}