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

使用P/Invoke从C#调用C++ DLL时返回异常数组值的问题

问题原因与解决方案

核心问题分析

  • C++参数传递逻辑错误:你的C函数中unsigned char *ptr是值传递,函数内部ptr = new unsigned char[5];仅修改了函数局部的指针副本,不会将新分配的数组地址传递回C#调用者。C#端通过Marshal.AllocHGlobal分配的内存从未被C函数写入,后续拷贝的是未初始化的随机内存,所以结果不符合预期。
  • C#调用参数不匹配:C#代码调用getData(ref ptr, shouldDetect)时多传了一个shouldDetect参数,但C++函数仅定义了一个参数,这会导致调用栈混乱,引发未定义行为。
  • 跨语言内存管理冲突:即使地址能传回,C++用new分配的内存无法通过C#的Marshal.FreeHGlobal释放——两者依赖的内存分配器不同,强行释放会导致内存泄漏或程序崩溃。

修复方案(两种常见可行思路)

思路1:C#预先分配内存,C++直接写入

这种方式避免跨语言内存管理问题,内存由C#全权负责分配和释放:

修正后的C++函数:

int getData(unsigned char *ptr) {
    // 直接写入调用者提供的内存,不再内部分配
    ptr[0] = 10;
    ptr[1] = 20;
    ptr[2] = 30;
    ptr[3] = 40;
    ptr[4] = 50;
    return 0;
}

修正后的C#代码:

using System.Runtime.InteropServices;

[DllImport(CppLibPath, CallingConvention = CallingConvention.Cdecl)]
// 无需ref,传递预先分配的内存地址让C++写入
private static extern int getData(IntPtr ptr);

public static void GetData() {
    var size = 5;
    var ptr = Marshal.AllocHGlobal(size);
    var arr = new byte[size];
    // 移除多余的shouldDetect参数,仅传递内存地址
    var result = getData(ptr);
    Marshal.Copy(ptr, arr, 0, size);
    Marshal.FreeHGlobal(ptr);
}

思路2:C++分配内存,配套释放函数

如果必须由C++分配内存,需同时提供对应的释放函数,禁止用C#的内存释放API:

C++端新增释放函数:

// 修改为接收指针的指针,实现地址回传
int getData(unsigned char **ptr) {
    *ptr = new unsigned char[5];
    (*ptr)[0] = 10;
    (*ptr)[1] = 20;
    (*ptr)[2] = 30;
    (*ptr)[3] = 40;
    (*ptr)[4] = 50;
    return 0;
}

// 配套释放函数,用delete[]释放new[]分配的内存
void freeData(unsigned char *ptr) {
    delete[] ptr;
}

C#端调用代码:

using System.Runtime.InteropServices;

[DllImport(CppLibPath, CallingConvention = CallingConvention.Cdecl)]
private static extern int getData(ref IntPtr ptr);

[DllImport(CppLibPath, CallingConvention = CallingConvention.Cdecl)]
private static extern void freeData(IntPtr ptr);

public static void GetData() {
    var size = 5;
    IntPtr ptr = IntPtr.Zero;
    var arr = new byte[size];
    // 移除多余的shouldDetect参数
    var result = getData(ref ptr);
    Marshal.Copy(ptr, arr, 0, size);
    // 调用C++的释放函数,不能用Marshal.FreeHGlobal
    freeData(ptr);
}

内容的提问来源于stack exchange,提问作者El_Merendero

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 10:17:18