Unity中C#与C++ DLL交互时字节数组及长度传递异常问题
Unity C# 与 C++ DLL 交互问题解决方案
核心问题定位
你的代码存在函数签名完全不匹配的致命问题:
- C# 声明
MyCppFunction返回byte[],但C++实现返回cv::Mat,两者的内存布局、返回机制完全不同,直接破坏了调用栈结构,导致messageSize参数被错误解析,出现长度值偏大的情况。 - 此外,C#与C++的参数传递逻辑也需要对齐,避免内存解析错误。
步骤1:修复输入参数传递问题
修正后的C#代码
using System.Runtime.InteropServices; using UnityEngine; void OnMessageReceived(CommsMessage message) { byte[] frameDataByteArray = message.payload.ToByteArray(); int frameDataLength = frameDataByteArray.Length; Debug.Log("Frame length in C# is: " + frameDataLength); // 初始化输出参数 IntPtr outputPtr = IntPtr.Zero; int outputLength = 0; // 调用修正后的C++函数 MyCppFunction(frameDataByteArray, frameDataLength, ref outputPtr, ref outputLength); // 后续处理返回的byte数组(见步骤2) } [DllImport("utility", CallingConvention = CallingConvention.Cdecl)] // 调整签名:输入用byte数组+长度,输出用指针和长度的引用传递 public static extern void MyCppFunction( [In] byte[] inputData, int inputSize, ref IntPtr outputData, ref int outputSize );
修正后的C++代码
#include <opencv2/opencv.hpp> #include <cstdlib> #include <cstring> // 必须加extern "C"避免C++名字混淆,同时显式指定__cdecl调用约定 extern "C" __cdecl void MyCppFunction(const unsigned char* inputData, int inputSize, unsigned char** outputData, int* outputSize) { std::cerr << "Received message size in C++: " << inputSize << std::endl; // 示例:将输入byte数组转为cv::Mat(根据你的实际数据格式调整构造逻辑) cv::Mat inputMat = cv::Mat(/* 替换为你的Mat尺寸/类型 */, inputData); // 业务处理逻辑... // 准备输出数据:分配内存并拷贝 *outputSize = inputMat.total() * inputMat.elemSize(); // 用malloc分配内存,方便C#端用Marshal.FreeHGlobal释放 *outputData = (unsigned char*)malloc(*outputSize); memcpy(*outputData, inputMat.data, *outputSize); }
步骤2:实现C++向C#返回byte数组
在C#中,需要将C++分配的指针转为byte数组,并手动释放内存避免泄漏:
// 在调用MyCppFunction后添加以下代码: if (outputPtr != IntPtr.Zero && outputLength > 0) { byte[] outputByteArray = new byte[outputLength]; Marshal.Copy(outputPtr, outputByteArray, 0, outputLength); // 必须释放C++中malloc的内存 Marshal.FreeHGlobal(outputPtr); // 处理outputByteArray的业务逻辑... }
关键注意事项
- 调用约定一致性:C#指定
CallingConvention.Cdecl,C必须显式声明__cdecl(MSVC默认是stdcall,会导致栈错误),同时用extern "C"避免C名字混淆。 - 数据类型对齐:C#的
int对应C++的int(32位,x86/x64平台一致),不要混用long或其他类型。 - 内存管理规则:C用
malloc分配的内存,必须在C#中用Marshal.FreeHGlobal释放;如果用new分配,需在C中提供专门的释放函数供C#调用。 - 字节序问题:x86/x64平台都是小端字节序,你的问题核心不是字节序,而是函数签名不匹配导致的栈破坏,无需优先处理字节序。
验证流程
- 先修复函数签名,验证C++端打印的
inputSize是否和C#端的frameDataLength一致; - 对比输入数组的前几个字节值,确认C++收到的
inputData正确; - 测试返回数组的长度和内容,确保数据完整无损坏。
内容的提问来源于stack exchange,提问作者Lucas B
相关产品推荐
相关产品推荐

