C++插件向C#传递int*与double*数组输出垃圾值如何解决
问题根因
你代码中出现垃圾值由两个核心错误导致:
- C侧指针参数是值传递,函数内
new操作修改的只是栈上的临时指针副本,并不会把新分配的内存地址传回C#调用方,C#侧AllocHGlobal申请的内存从未被写入有效数据,同时C侧new的内存直接泄漏。 - C#侧
Marshal.AllocHGlobal的入参是字节数,你直接传数组长度16、24,申请的内存大小远小于存储16个int(需164=64字节)、24个double(需248=192字节)的需求,就算写入正确也会触发内存越界。
推荐解决方案(C#分配内存,无跨堆释放风险)
这种方案内存管理全在C#侧,不需要额外处理内存释放逻辑,是跨语言交互的首选实现。
修改后C++代码
移除new操作,直接往C#传入的内存地址写入数据即可:
extern "C" __attribute__ ((visibility ("default"))) void funcplugin(int* corners, double* points) { // 无需再分配内存,直接填充数据 for(int i=0; i<16; i++){ corners[i] = i; // 替换为你实际的计算逻辑 } for(int i=0; i<24; i++){ points[i] = i * 1.0; // 替换为你实际的计算逻辑 } }
修改后C#代码
两种实现可选:
1. 简化自动封送版(无需手动管理内存)
[DllImport ("native")] // 用[In, Out]特性告知运行时需要把非托管侧的修改回传到托管数组 private static extern void funcplugin([In, Out] int[] corners, [In, Out] double[] points); void call() { int[] first = new int[16]; double[] second = new double[24]; // 直接传数组即可,运行时自动处理封送逻辑 funcplugin(first, second); for (int i=0; i<16; i++) { Debug.Log("corners: " + first[i]); } for (int j=0; j<24; j++) { Debug.Log("points " + second[j]); } }
2. 手动内存分配修正版
private int size_corners =16; private int size_points =24; [DllImport ("native")] private static extern void funcplugin(IntPtr corners, IntPtr points); void call() { int[] first = new int[size_corners]; double[] second = new double[size_points]; // 修正内存分配的字节数计算 IntPtr corners = Marshal.AllocHGlobal(size_corners * sizeof(int)); IntPtr points = Marshal.AllocHGlobal(size_points * sizeof(double)); funcplugin(corners, points); Marshal.Copy(corners, first, 0, size_corners); Marshal.Copy(points, second, 0, size_points); for (int i=0; i<16; i++) { Debug.Log("corners: " + first[i]); } for (int j=0; j<24; j++) { Debug.Log("points " + second[j]); } // 释放非托管内存 Marshal.FreeHGlobal(corners); Marshal.FreeHGlobal(points); }
可选方案(C++分配内存,适配必须在native侧分配的场景)
如果业务逻辑要求必须在C++侧分配内存,需要将参数改为二级指针传递,同时配套释放函数避免内存泄漏:
修改后C++代码
extern "C" __attribute__ ((visibility ("default"))) void funcplugin(int** corners, double** points) { *corners = new int[16]; *points = new double[24]; // 填充数据 for(int i=0; i<16; i++){ (*corners)[i] = i; } for(int i=0; i<24; i++){ (*points)[i] = i * 1.0; } } // 必须提供对应的释放函数,避免跨堆释放异常 extern "C" __attribute__ ((visibility ("default"))) void free_plugin_mem(int* corners, double* points) { delete[] corners; delete[] points; }
修改后C#代码
[DllImport ("native")] private static extern void funcplugin(out IntPtr corners, out IntPtr points); [DllImport ("native")] private static extern void free_plugin_mem(IntPtr corners, IntPtr points); void call() { int size_corners =16; int size_points =24; int[] first = new int[size_corners]; double[] second = new double[size_points]; IntPtr corners, points; funcplugin(out corners, out points); Marshal.Copy(corners, first, 0, size_corners); Marshal.Copy(points, second, 0, size_points); // 调用C++侧的释放函数释放内存 free_plugin_mem(corners, points); for (int i=0; i<16; i++) { Debug.Log("corners: " + first[i]); } for (int j=0; j<24; j++) { Debug.Log("points " + second[j]); } }
内容的提问来源于stack exchange,提问作者Neet
相关产品推荐
相关产品推荐

