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关键字的运作逻辑很直接:
- 调用非托管函数前,C#在栈上为
MyStruct实例分配好内存空间。 - 将该栈内存的地址作为指针传递给C++函数。
- C++函数直接通过指针写入这块内存(比如
outStruct->value1)。 - 函数返回后,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
相关产品推荐
相关产品推荐

