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

C# P/Invoke调用C++时out结构体参数初始化及内存问题咨询

C++/C#互操作:结构体内存分配与out参数机制解析

为什么new MyStruct()无法正确传回数据

你在C++代码里用new MyStruct()的操作完全无效,核心原因是:

  • C#调用GetValues(out result)时,已经在栈上为值类型MyStruct分配了内存,并把这块内存的地址传递给C++函数的outStruct指针参数。
  • new MyStruct()是在C++堆上分配新内存,然后修改了函数内部的outStruct指针副本——但这根本没触及C#传入的原始栈内存地址。
  • 函数返回后,C#还是从原来的栈内存读取数据,自然拿不到正确结果,同时C++堆上的内存还会泄漏。

C# out参数的工作机制

针对值类型(比如结构体),out关键字的运作逻辑很直接:

  1. 调用非托管函数前,C#在栈上为MyStruct实例分配好内存空间。
  2. 将该栈内存的地址作为指针传递给C++函数。
  3. C++函数直接通过指针写入这块内存(比如outStruct->value1)。
  4. 函数返回后,C#从栈内存读取数据填充到result变量中。

全程内存分配由C#托管代码负责,C++只需要完成数据写入,不需要手动分配内存。

微软官方文档的相关说明

微软在.NET互操作文档中明确了这类场景的规范:

  • 在值类型封送处理章节中提到:用out或ref修饰值类型参数时,.NET会传递变量的内存地址给非托管代码,非托管代码直接修改该地址指向的内存即可,无需额外分配。
  • 在托管与非托管代码间传递结构体的文档中,针对值类型结构体的输出参数,明确要求非托管函数接收指针后直接写入数据——因为托管端已经完成了内存的分配与管理。

正确代码示例

C++ 代码

struct MyStruct {
    int value1;
    float value2;
};
    
extern "C" __declspec(dllexport) void GetValues(MyStruct* outStruct) {
    // 直接写入传入的内存地址,无需new分配
    outStruct->value1 = 42;
    outStruct->value2 = 3.14f;
}

C# 代码

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
    public int value1;
    public float value2;
}
    
[DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void GetValues(out MyStruct result);
    
public static void TestInterop() {
    MyStruct result;
    GetValues(out result);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:20:06