SWIG基础知识

SWIG是一种简化C++到其他语言(如C#)接口封装的工具,它生成C代码并编译为DLL库,然后自动生成C#调用代码。通过类型映射机制处理参数转换,支持类、方法与参数封装,方便进行C++接口的跨语言调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SWIG基本介绍

C++到其他语言的包装器,本质上还是与其他高级语言使用传统方式调用C++代码的方式相同(如C#的Pinvoke,JAVA的NDK等),而SWIG只是帮助我们简化这个流程,不用为每个类每一个接口手写封装代码(SWIG不是做代码的转换,而是调用封装)。
基本流程:SWIG将C++代码转换为各个语言可以调用的C代码(生成CXX文件,这个文件的C代码内部调用C++的接口),将CXX代码编译成DLL库。之后封装成各自语言调用C++的C#代码(这部分代码生成的是 工程名_PINVOKE.cs 命名的C#文件),最后将类封装成C#的代理类.

基本使用

  • 编写脚本文件(即告诉C++的哪些类、哪些接口、使用什么转换规则来封装C++的一个脚本文件)
//脚本文件 example.i
%module(directors="1") exmaple
%{
#include "aaa.h"   //C++的cxx代码所需要包含的头文件,
%}

%include "aaa.h"  //需要将C++的接口文件封装到C#类中,如果这个头文件内部有多个类,对应生成多个C#的类文件.
//如果使用 %import "aaa.h" 那么代表是从另一个SWIG接口文件或头文件中收集某些信息,而不实际生成任何包装器代码。
//执行脚本文件;
swig.exe -c++ -csharp example.i 
//执行之后生成的文件有:
aaa.cs exmaple.cxx exmaple_pinvoke.cs 文件

类封装

class Example
{
public:
  int add(int x,int y)
  {
  return x+y;
  }
};

常用的类的封装修改说明

## 修改类名
%rename(Simple) Example //修改C#的封装类类名
## 修改类的访问类型
%typemap(csclassmodifiers) SWIGTYPE "protected class" 
## 修改构造函数的访问方式
SWIG_CSBODY_PROXY(public, public, Example) //默认在其他模块中可能不能继承,有些构造函数是保护类型
## 修改C#中方法的访问方式
%csmethodmodifiers Example::add "protected"
## 给C++类中添加扩展方法
%extend //$self 如果需要访问内部的成员变量,需要将变量通过公有方法来访问,$self是当前对象的指针,不能使用this代替;
{
  bool sub(int x,int y)
  {
    return x-y;
  }
}
//添加的方式是目标代码,内部代码是C#代码,这个是与%extend的区分
%proxycode %{
public String toString() {
boolean flag = FetchFlag();
return Boolean.toString(flag);
}
%}

## 给C#代理类增加成员变量和C#方法
%typemap(cscode) Example %{
  private int const_value=5;
  public void plus(int x,int y) {
  return x+y-const_value;
  }
%}

## 修改整个代理类(需要注意,如果有多个地方修改了代理类,只使用最后一个)
  //typemap(csbody) 这个是非继承类 typemap(csbody_derived) 这个是继承类,对于模板类修改这个代理类的方式也是生效;
%typemap(csbody_deviced) Example %{
     private global::System.Runtime.InteropServices.HandleRef swigCPtr;
	 protected bool swigCMemOwn;
      public $csclassname(global::System.IntPtr cPtr, bool cMemoryOwn) {
      swigCMemOwn = cMemoryOwn;
      swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
  }
}
  
## 添加一个C++不存在的类
%pragma(csharp) imclassimports=%{
using System.Reflection;
using System.IO;
using System.Collections;
using System;
using System.Collections.Generic;
public class SwigAssembly
{
    
}
%}
    
## 将一个类设置为回调类,可以由其他语言继承,dirprot是否对包含的方法继承;
%feature("director","dirprot"="1") Example;
## 将一个模板类设置封装到C#中
%template(ExampleList)dan::List<Example>;
    
    
##修改由C++转为C#的方法(如希望改写C++某个方法的实现,或者为这个方法增加额外的实现),
##也可以是修改C#需要继承的某个方法。 也可以定义某个变量的输出类型代码
 //dan::Smart_Object<ISGDrawControl> createObject 这个是函数名字(不需要带上函数参数名)
 %typemap(csout, excode=SWIGEXCODE) dan::Smart_Object<ISGDrawControl> createObject {  
    global::System.IntPtr cPtr =$imcall; //这部分代码是由C++转C#的实现代码
   if(cPtr==null)
   {
	   return null;
   }
   var result_val= new ISGDrawControl(cPtr,true);
   result_val._init();
   return result_val;
} 

    
// 保护方法继承

ps: %feature,%template类似的定义其实是SWIG中的宏,这种宏与我们的C++宏类似,在SWIG种定义了很多这种宏,当然我们也可以定义宏;

方法与参数封装

方法的封装更多的是参数的封装问题,SWIG有一套类型映射机制,简单来说就是一套规则,告诉swig如何将这些矛盾化解,并定义名称参数,将名称参数写道接口文件的类和函数声明。

##方法命名修改
%rename(plus) add;//在类中修改;
参数处理
  • 输入参数转换(in、csin 类型映射)
  • 重载方法中的输入参数类型检查(typecheck 类型映射)
  • 输出参数处理(argout 类型映射)
  • 输入参数值检查(check 类型映射)
  • 输入参数初始化(arginit 类型映射)
  • 默认参数(default 类型映射)
  • 输入参数资源管理(freearg 类型映射)
  • 输出参数转换( out、csout 类型映射)

作为回调类的输入参数与正常的输入参数不同。类似的有 directorin、csdirectorin、csdirectorin、csdirectorout

swig基本类型说明
  • swigtype 代表的是C++的当前类型,也可理解为通用类型
  • ctype 代表是C语言中的类型(C++转C语言代码,只有基础类型和指针,所以类的处理大部分都是处理为指针类型)
  • cstype 代表的是C#中的类型
## 综合示例 自定义字符串类型SGString与C#String类型的转换
//我们需要明白的是,SGString和String是两个不同的类,与SGString封装的代理类不同的是,C#的String不是一个代理类,它是C#中一个普通的类,SGString和String
//转换的中间条件是一定要能够转到基础类型中(SGString和String的基础类型是char*)
## 第一步,我们需要规定C++类型(SGString)对应的C#类型(String) 
//需要注意的是SGString与const SGString&,SGString&,SGString是不同的类型,全面支持这几种类型需要多重复几次;
%typemap(ctype) SGString "char *" //C++类型到C类型(原类型SGString类型,char*类型是C类型)
%typemap(imtype) SGString "string" //C++到C#的中间类型,一般情况下等于C#类型,不同过多的考虑
%typemap(cstype) SGString "string"//C++类型到C#类型,明确这两种类型的关系;
## 第二步,确定C++类型到C类型的映射
//输入映射,从C++到C类型的映射,类型是SGtring类型,当然这个还可以有各种过滤
//如%typemap(in) SGString name 代表的是只对参数名为name的SGString类型生效
    
%typemap(in) SGString //注意的是SGString*,const SGString&与SGString不是同一个参数类型,如果要支持多个类型需要用逗号分开
%{ if (!$input) {  //$input是输入参数;
    return $null;
   }
   $1=$input.c_str();//$1是输入参数的中间参数,我们需要将输入参数转到中间参数,这个里面我们只有一个输入参数.
 %}

%typemap(out) SGString %{ $result = $1.c_str(); %} //$result 为返回值标记;
## 第三步 确定回调类中SGString类型的处理方式;
//回调类中SGString作为参数的处理;
%typemap(directorout) SGString 
%{ if (!$input) {
    return $null;
   }
   $result=$input.c_str();
 %}

%typemap(directorin) SGString   //回调类从C#传入值到C++中;
%{ 
 $input =$1.c_str(); 
%}
## 第四步 确定在C#代码中,对于SGString的处理方式(在开始的时候确定了SGString在C#表示为String);
%typemap(csin) SGString "$csinput"
%typemap(csout) SGString {
    string ret = $imcall;$excode
    return ret;
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

揽月凡尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值