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

C# P/Invoke调用C++接口时Struct8非ref传递出现内存损坏问题

问题根本原因

P/Invoke签名与C导出函数的参数类型不匹配:
你C
侧导出的Net5_Initialize函数所有结构体参数均为指针类型:

MODULE_API void Net5_Initialize(Struct1* struct1, Struct8* struct8, Struct6* struct6, Struct2Detail* struct2Detail);

但你最初的C# DllImport声明中,Struct1、Struct8是按值传递的:

// 错误声明
[DllImport(LIBNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void Net5_Initialize(Struct1 struct1, Struct8 struct8, out Struct6 struct6, out Struct2Detail struct2Detail);

C#按值传递值类型结构体时,会把结构体完整内容复制到调用栈中,而C侧会把栈上的结构体数据直接当成内存指针访问,必然会访问非法内存,导致参数内容损坏。你给Struct8加上ref修饰后,C#会改为传递结构体的内存地址,刚好匹配C的Struct8*类型,所以调用可以正常运行。

为什么其他参数看起来没出问题?

你代码中out修饰的参数本身就是传地址,天然匹配C++的指针类型,所以没有问题。其他按值传递的结构体参数(比如Create接口中的Struct1、Struct3、Struct5)本质上也存在类型不匹配问题,只是暂时没有触发崩溃,属于不稳定的巧合状态。

修复方案

  1. 修正所有P/Invoke签名,所有对应C++侧为结构体指针的参数,都加上ref/out修饰,可额外添加[In]/[Out]特性明确封送方向:
// 修正后的Net5_Initialize声明
[DllImport(LIBNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void Net5_Initialize(
    [In] ref Struct1 struct1,
    [In] ref Struct8 struct8,
    out Struct6 struct6,
    out Struct2Detail struct2Detail
);
  1. 同步修改上层封装的方法签名:
public static void Initialize(
    Struct1 struct1,
    ref Struct8 struct8,
    out Struct6 struct6,
    out Struct2Detail struct2Detail
)
{
    Net5_Initialize(ref struct1, ref struct8, out struct6, out struct2Detail);
}
  1. 逐个检查所有P/Invoke接口的参数类型,确保C#侧的参数传递语义和C++侧完全匹配,避免隐藏的崩溃风险。

额外说明

你当前的StructLayout、MarshalAs配置是正确的,C#与C++侧的结构体内存布局完全对齐,不需要修改结构体定义。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 12:06:02