You need to enable JavaScript to run this app. C#如何将uint[]数组传递给C++ DLL的unsigned long*指针参数
优惠活动
大模型
产品
解决方案
定价
更多

C#如何将uint[]数组传递给C++ DLL的unsigned long*指针参数

报错根因

运行时报错:无法将uint[]转换为int[]

你当前的代码存在两个核心问题,共同导致了运行异常:

  • 方法重载匹配失败:调用Marshal.Copy时,没有正确匹配到uint[]对应的方法重载,编译器尝试将uint[]转换为重载要求的int[]参数类型,最终抛出上述类型转换错误。
  • 非托管内存分配大小错误:你当前使用IDs.Length作为内存分配长度,仅分配了和元素数量相等的字节数,没有考虑每个uint(对应C++端32位unsigned long,固定占4字节)的实际内存占用,会直接导致内存越界。该问题即使解决了类型转换报错,也会触发内存越界,导致程序随机崩溃。
正确实现方案

1. 结构体定义适配确认

你当前编写的C#侧ST_TEST结构体定义是完全正确的:

[StructLayout(LayoutKind.Sequential)]
public struct ST_TEST
{
    public IntPtr anIDs; // 对应C++的unsigned long*指针,自动适配32/64位指针宽度
    public uint anIDCount; // 对应C++的unsigned long,Windows平台MSVC编译下长度、符号完全匹配
}

注:Windows平台下MSVC编译器采用LLP64数据模型,无论32位还是64位编译目标,unsigned long始终为32位,与C#的uint类型完全兼容,不需要做额外类型转换。

2. 修正后的非托管内存操作代码

uint[] IDs = { 12824874, 7865845, 45875792 };

ST_TEST stTest = new ST_TEST();
stTest.anIDCount = (uint)IDs.Length;

// 按数组实际占用的内存总长度分配非托管内存
IntPtr buffer = Marshal.AllocHGlobal(IDs.Length * sizeof(uint));
try{
    // 匹配uint[]对应的Marshal.Copy重载,不存在类型转换问题
    Marshal.Copy(IDs, 0, buffer, IDs.Length);
    stTest.anIDs = buffer;
    // 此处编写调用C++ DLL的逻辑
}
finally
{
    // 必须确保C++ DLL调用完全结束后再释放内存
    Marshal.FreeHGlobal(buffer);
}

3. 旧版本兼容处理

如果使用的旧版.NET框架环境未提供Marshal.Copy(uint[], IntPtr, int, int)重载,可通过不安全代码逐元素写入内存,绕开重载不匹配的问题:

unsafe
{
    uint* pIDs = (uint*)buffer;
    for (int i = 0; i < IDs.Length; i++)
    {
        pIDs[i] = IDs[i];
    }
}
注意事项
  • 内存释放时序:绝对不能在C++ DLL调用执行完成前释放非托管内存,否则会导致C++端读取指针时触发访问违规崩溃。
  • 结构体对齐:如果C++端的ST_TEST结构体存在自定义对齐规则,需要在C#端的StructLayout特性中补充对应的Pack参数,保证两端内存布局完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 06:54:07