You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 04:21:04