C#调用C++ DLL传递数组时读取到错误值的问题咨询
错误原因
你的代码存在三处直接导致数值异常的不匹配问题:
- 封送类型不匹配:C#端标记
UnmanagedType.SafeArray时,封送层会把托管数组转成COM规范的SAFEARRAY结构,但C端声明的接收类型是std::vector<int>*,二者内存布局完全不同,硬解析必然得到错误值。std::vector是C标准库实现的容器,和COM SAFEARRAY没有任何二进制兼容性,且跨模块(甚至同语言不同编译配置下)传递STL容器本身就存在布局不一致的风险,不适合直接做跨语言互操作的参数类型。 - 指针访问逻辑错误:退一步说,就算传入的是合法的
std::vector<int>*指针,curveTags[0]取到的是指针指向的std::vector对象本身,而非vector存储的第一个int元素,正确的元素访问写法是(*curveTags)[0]或curveTags->at(0),现有写法是把vector对象的头部内存(通常是内部数据指针、长度、容量三个字段)直接当int解析,值不可能正确。 - 没有传递数组长度:就算类型匹配,只传容器/数组指针不带长度,C++端也无法安全判断数组边界,后续遍历很容易出现越界访问。
修复方案
跨语言互操作传递数组最稳妥的方式是使用原始连续内存指针+长度参数,不要直接封送SAFEARRAY或跨语言传递STL容器,两边代码修改如下:
C# 端代码
移除SafeArray封送标记,直接传递托管数组和数组长度,默认封送规则会自动把托管int数组转为C++可直接访问的连续int内存块:
[DllImport("DLL1.dll", CallingConvention = CallingConvention.StdCall)] public static extern void GMSH_PassVector(int[] curveTag, int tagLength); // 调用逻辑 int[] curveTagArray = { 1, 2, 3, 4 }; GMSH_PassVector(curveTagArray, curveTagArray.Length);
C++ 端代码
把头文件声明和实现都改为接收原始int指针和长度参数:
// 头文件声明 extern "C" GMSH_API void GMSH_PassVector(int* curveTags, int tagLength); // 函数实现 void GMSH_PassVector(int* curveTags, int tagLength) { // 打印首元素 printf("首元素值:%d \n", curveTags[0]); // 需要遍历所有元素时直接按索引访问即可 for (int i = 0; i < tagLength; i++) { printf("第%d个元素:%d\n", i, curveTags[i]); } }
如果业务逻辑需要使用std::vector,直接在C++函数内部基于传入的指针和长度构造本地vector即可,不需要跨语言传递STL对象:
void GMSH_PassVector(int* curveTags, int tagLength) { std::vector<int> tagVec(curveTags, curveTags + tagLength); // 后续基于本地tagVec实现业务逻辑 printf("vector首元素:%d\n", tagVec[0]); }
注意:该传参方式下,封送层会在非托管函数执行期间临时锁定托管数组的内存位置,避免GC移动内存,函数返回后锁定自动解除。不要在非托管代码中长期保存该指针(比如存到全局变量在函数返回后使用),否则会触发野指针访问异常。
内容的提问来源于stack exchange,提问作者Aris Theo
相关产品推荐
相关产品推荐

