如何在SWIG中映射Person*&?实现C#端ref Person[]调用方式
实现C#中以
ref Person[]调用SWIG生成的C++函数 核心思路
SWIG默认对C的Person*&(指针引用)类型处理会生成SWIGTYPE_p_p_Person这类不友好的包装类型,要实现C#侧ref Person[]的调用形式,需要通过自定义SWIG类型映射来完成C#数组与C指针之间的双向转换,同时处理内存管理。
方案一:使用SWIG类型映射实现目标调用形式
在你的SWIG接口文件(.i)中添加以下配置,完成类型转换逻辑:
%module PersonModule // 引入std_string支持,处理Person的name字段 %include "std_string.i" // 封装Person类 class Person { public: std::string name; }; // 定义Person*&的类型映射,对接C#的ref Person[] %typemap(ctype) Person*& "Person**" %typemap(imtype) Person*& "ref Person[]" %typemap(cstype) Person*& "ref Person[]" // 输入映射:将C# Person[]拷贝到C++堆数组 %typemap(in, numinputs=1) Person*& (Person* temp_ptr) { $1 = &temp_ptr; if ($input != IntPtr.Zero) { const int input_len = $input.Length; temp_ptr = new Person[input_len]; // 逐个拷贝Person对象的字段 for (int i = 0; i < input_len; ++i) { temp_ptr[i].name = $input[i].name; } } else { temp_ptr = nullptr; } } // 输出映射:将C++新分配的Person数组转换为C# Person[] %typemap(argout) Person*& { // 注意:原函数固定生成3个元素,若为动态长度需额外传递长度参数 const int output_len = 3; Person[] result_arr = new Person[output_len]; for (int i = 0; i < output_len; ++i) { result_arr[i] = new Person(); result_arr[i].name = (*$1)[i].name; } // 将结果赋值回C#的ref参数 $input = result_arr; } // 标记函数返回的指针为堆分配,需后续释放 %newobject GetPersonArrayRef; // 封装目标函数 void GetPersonArrayRef(Person*& p); // 添加内存释放函数,避免内存泄漏 %inline %{ void FreePersonArray(Person* arr) { delete[] arr; } %}
调用示例(C#)
// 初始化输入数组 Person[] inputList = new Person[5]; for (int i = 0; i < 5; ++i) { inputList[i] = new Person { name = $"InputName{i}" }; } // 调用目标函数 PersonModule.GetPersonArrayRef(ref inputList); // 使用输出的数组 foreach (var p in inputList) { Console.WriteLine(p.name); } // 释放C++端分配的内存 PersonModule.FreePersonArray(inputList);
方案二:修改C++代码添加适配函数(简化版)
如果类型映射配置过于复杂,可以在C++侧新增一个适配函数,将指针引用拆分为更易SWIG处理的参数:
// 新增适配函数 void GetPersonArrayAdapter(Person* input_arr, int input_len, Person*& output_arr, int& output_len) { // 原函数的遍历逻辑 for (int i = 0; i < input_len; ++i) { std::cout << input_arr[i].name << std::endl; } // 原函数的数组分配逻辑 Person p0, p1, p2; p0.name = "0name"; p1.name = "1name"; p2.name = "2name"; output_arr = new Person[3]{ p0, p1, p2 }; output_len = 3; }
然后在SWIG接口文件中封装这个适配函数,C#侧调用时只需传入输入数组、长度,再接收输出数组和长度,自行转换为Person[]即可,无需复杂的类型映射。
注意事项
- 内存管理:原C++函数中
new分配的数组必须手动释放,否则会造成内存泄漏,建议通过SWIG封装的FreePersonArray函数处理。 - 动态长度:如果原函数的输出数组长度是动态的,需要在函数中额外返回长度参数,修改类型映射中的
output_len逻辑。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

