.NET调用C++编写的Salary DLL传递stOutput结构体数组返回垃圾值求助
问题核心原因
- .NET 端结构体未指定内存布局规则,默认情况下CLR会自动调整结构体成员的内存排布顺序以优化空间,和C++端严格按声明顺序排布的结构体内存布局完全不匹配,导致封送时读取的内存位置错误。
- C++端指定了
#pragma pack(8)的对齐规则,.NET端未显式指定对齐参数,两边内存对齐规则不一致会导致成员偏移量错位。 - 你实际传参为结构体数组,但当前.NET的函数声明仅按单个结构体引用传参,数组的内存封送逻辑错误,导致越界读取垃圾值。
解决方案
1. 修正.NET端结构体定义
显式指定结构体的顺序布局和对齐规则,成员顺序必须和C++端完全一致,不能遗漏任何中间成员:
<StructLayout(LayoutKind.Sequential, Pack:=8)> Public Structure stOutput Public lDate As Integer ' 其余中间成员严格按照C++端的声明顺序、对应类型填写 Public dMoney As Double End Structure
修改完成后先验证两边结构体大小是否一致:C++端用sizeof(stOutput)打印大小,.NET端用Marshal.SizeOf(GetType(stOutput))打印,二者数值必须完全相等,否则继续排查成员类型、顺序问题。
如果仅需要传递单个结构体,做完这一步后原有的函数声明不用修改,即可正常拿到返回值。
2. 修正函数声明适配数组传参
如果是传递结构体数组的场景,需要调整封送规则,同时建议补充数组长度参数避免越界操作:
首先调整C++端导出函数,增加数组长度入参:
extern "C" long FuncExport __stdcall Calc_Salary(stOutput *Output, long arrayLen);
对应修改.NET端的函数声明:
Public Declare Function Calc_Salary Lib "Salary" _ (<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Output As stOutput(), ByVal arrayLen As Integer) As Integer
调用时直接传递数组名和数组长度即可,不需要加ByRef,数组作为引用类型会自动传递内存地址,封送器会根据你指定的数组长度完成双向内存拷贝。
额外校验点
- 确认C++端结构体中的
Double为标准8字节双精度浮点数(正常使用小写double即可,大写属于自定义别名的话要确认底层类型一致),和.NET端的Double类型长度匹配。 - 确认你C端的
long类型在当前编译平台下为4字节(Windows平台32/64位下long均为4字节,和.NET的Integer匹配;如果是跨Linux平台需要调整为C的int32_t对应.NET的Integer)。
内容的提问来源于stack exchange,提问作者user13232877
相关产品推荐
相关产品推荐

