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

如何在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[]即可,无需复杂的类型映射。


注意事项

  1. 内存管理:原C++函数中new分配的数组必须手动释放,否则会造成内存泄漏,建议通过SWIG封装的FreePersonArray函数处理。
  2. 动态长度:如果原函数的输出数组长度是动态的,需要在函数中额外返回长度参数,修改类型映射中的output_len逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:16:21