C#通过结构体指针向C DLL传递结构体数组的P/Invoke调用问题
问题根因
- 你当前的
[DllImport]签名使用ref DATA pData声明参数时,封送层默认仅会封送单个DATA结构体大小的内存块到非托管侧,不会自动识别并拷贝托管堆上整个连续的DATA数组。 - C端拿到指针后按传入的数组长度做指针偏移访问后续元素时,读取的是未被正确封送的非法内存,直接导致第二个及之后的结构体字段出现乱码、数值错误。
- 你参考的字节数组
ref arr[0]传参能生效,是因为byte是可直接内存拷贝的blittable基元类型,封送器对基元类型数组的ref首元素传参有特殊处理,但自定义结构体数组直接ref首元素不会触发该逻辑。
正确实现方案
你的DATA结构体本身的封送定义是正确的:32定长字节数组+32位int的内存布局和C端完全匹配,不需要调整。以下两种方案任选其一即可:
方案1:直接声明数组参数(最简洁,推荐日常使用)
直接修改P/Invoke签名,将第一个参数声明为数组类型,让封送器自动处理整个数组的连续内存拷贝:
[DllImport("a.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void test_data( [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] DATA[] pData, // 严谨匹配C端DWORD的话可以把length类型改成uint int length );
特性说明:
[MarshalAs(UnmanagedType.LPArray)]明确告知封送器该参数对应非托管侧的连续数组SizeParamIndex = 1指定数组长度由签名中索引为1的参数(即length参数)提供
调用时直接传入整个数组即可,不需要传数组首元素的ref:
int length = 10; DATA[] arr = new DATA[length]; for(int i = 0; i < length; i++){ arr[i].name = new byte[32]; arr[i].age = 10; } // 直接传数组,无需ref arr[0] test_data(arr, length);
方案2:手动分配非托管内存(高性能场景适用)
如果调用频率高、数组长度大,想要避免封送器的默认拷贝开销,可以手动在非托管堆分配连续内存,自行完成结构体拷贝,调用完成后释放内存:
首先修改P/Invoke签名,接收非托管指针类型:
[DllImport("a.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void test_data(IntPtr pData, uint length);
调用逻辑:
int length = 10; DATA[] arr = new DATA[length]; for(int i = 0; i < length; i++){ arr[i].name = new byte[32]; arr[i].age = 10; } int structSize = Marshal.SizeOf<DATA>(); // 分配对应长度的连续非托管内存 IntPtr pUnmanagedArray = Marshal.AllocHGlobal(structSize * length); try { // 按偏移将每个托管结构体拷贝到非托管内存 for (int i = 0; i < length; i++) { IntPtr pCurrentStruct = pUnmanagedArray + i * structSize; Marshal.StructureToPtr(arr[i], pCurrentStruct, false); } // 调用C端函数 test_data(pUnmanagedArray, (uint)length); } finally { // 必须释放非托管内存,避免内存泄漏 Marshal.FreeHGlobal(pUnmanagedArray); }
额外避坑提示
- 你贴出的C端代码存在变量名笔误:函数入参命名为
pStruct,但函数内部遍历使用的是pData,直接编译会报错,需要统一变量名。 - C端
DWORD是32位无符号整数,日常使用传int类型不会有问题,但如果数组长度可能超过int最大值,建议将C#侧对应参数改为uint做严格匹配。 - 不要对自定义结构体数组使用
ref arr[0]的传参方式,封送器不会自动遍历拷贝整个数组,本质上和传单个结构体的引用没有区别。
内容的提问来源于stack exchange,提问作者of32 inc
相关产品推荐
相关产品推荐

