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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:57:32