当前位置: 首页 > news >正文

陕西省交通集团建设网站网站服务器

陕西省交通集团建设网站,网站服务器,室内设计师一个月多少钱,网站套餐报价SWIG系列:http://t.csdn.cn/cIAcr 文章目录一、简介二、全局函数、变量、常量三、继承四、传递指针、引用、数组与值五、基本类型的指针与引用六、基本类型的数组七、基本类型的默认map规则八、常用的typemap方法九、代码插入十、实践10.1 如何映射Foo*&到ref F…

SWIG系列:http://t.csdn.cn/cIAcr

文章目录

  • 一、简介
  • 二、全局函数、变量、常量
  • 三、继承
  • 四、传递指针、引用、数组与值
  • 五、基本类型的指针与引用
  • 六、基本类型的数组
  • 七、基本类型的默认map规则
  • 八、常用的typemap方法
  • 九、代码插入
  • 十、实践
    • 10.1 如何映射Foo*&到ref Foo
    • 10.2 映射Foo* array数组
    • 10.3 如何将char**映射为string[]
    • 10.4 如何映射C++的容器(vector\pair)
    • 10.5 如何映射函数指针
  • 十一、要点总结

一、简介

SWIG如何实现让C#方便的调用C++函数的?

其实原理并不负责,仍然使用C#的互操作技术P/Invoke实现,只不过SWIG对C++代码进行的包装,使开发者更易于调用。

生成C#代码时注意可选添加几个额外的命令行选项:

  • -dllimport :指定P/Invoke时要调用的dll名称
  • -namespace :设置C#的命名空间
  • -outfile :将所有生成的C#代码放到一个cs文件中

二、全局函数、变量、常量

int a = 0;
void funA();
#define PI 3.14class Foo
{
public:
int * bar(int* items);
};

因C#里没有全局成员的概念,所以SWIG都把它们生产到了与%module同名的类里,且都是静态成员,可直接访问。
在这里插入图片描述

三、继承

class Foo
{
};class Bar : public Foo
{};

以上的c++代码SWIG可以完整的生成为C#代码,并且保留继承关系:

public class Foo
{
};pulic class Bar : Foo
{};

注意:因C#里没有多继承,所以如果C++里的代码是多继承的,则生成的C#代码只会继承第一个父类。

四、传递指针、引用、数组与值

class Foo
{
public:void spam1(Foo* x);  // 传指针void spam2(Foo& x);  // 传引用void spam3(Foo x);   // 传值void spam4(Foo x[]); // 传数组
};

由于SWIG认为一切皆是指针,所以上面的Foo* Foo& Foo Foo[]四种类型并没有什么区别,生成C#代理类后调用方式都一样:

var f = new Foo();
f.spam1(f);
f.spam2(f);
f.spam3(f);
f.spam4(f); //接收是数组,但是我们只传了一个值进去。不符合期望,后续要做处理。

同理,对于函数的返回值类型来说,以下也没有什么区别:

class Foo
{
public:Foo* spam1();Foo& spam2();Foo  spam3();
};

五、基本类型的指针与引用

如果未做特殊说明,这里的基本类型指的就是int、long、bool、char、float等这些类型,非自己定义的类。

class Foo
{
public:void add(int* a, int* b, int* result) {*result = *a + *b;}
};

默认情况下指针和引用会被生成为以SWIGTYPE_开头的C#类型:

public void add(SWIGTYPE_p_int a, SWIGTYPE_p_int b, SWIGTYPE_p_int result) 
{
}

对于这些不太友好的类型,需要编写.i文件进行映射,将其映射为C#的int类型:

%include <typemaps.i>%apply int *OUTPUT {int * result};
%apply int *INPUT {int *a,int *b};

生成如下易于调用到C#代码:

public void add(int a, int b, out int result) 
{
}

同理,引用类型的处理也是类似,可以将其映射为c#的ref

%include <typemaps.i>  //添加SWIG自带的库%apply bool& INOUT {bool&};

注:在上述过程中,我们并没有自己定义typemap。因为以上的操作SWIG已经帮我们实现了只是默认没有这么做而已,其实现的代码就是写在了<typemaps.i>库,我们只需要将其%apply一下。

六、基本类型的数组

C++里的int*即可以表示单个对象,也可以表示一个数组。这里演示如何将其映射为C#的数组。

class Foo
{
public:void copy(int* source, int* target, int count){}
};

可以通过如下的定义将上述数组转为C#的数组:

%include <arrays_csharp.i>   // 添加SWIG自带的库
// apply一下
%apply int INPUT[] {int * source}
%apply int OUTPUT[] {int * target}

然后就生成了如下的C#代码:

public void copy(int[] source, int[] target, int count) {
demoModulePINVOKE.Foo_copy(swigCPtr, source, target, count);
}

调用起来非常之方便,我们观察下demoModulePINVOKE.Foo_copy方法的实现:
在这里插入图片描述
原来是通过Marshal将C#数组元素的首指针封送了过去。

七、基本类型的默认map规则

部分C++类型映射到C#类型的规则如下:
在这里插入图片描述
更多默认规则,下载完SWIG之后,使用Everything软件搜索csharp.swg文件即可。

八、常用的typemap方法

在这里插入图片描述
是否还记得前几篇文章介绍typemap时的哪些in、out、freeargs方法? 上图里的方法也属于同等范畴,只不过是特定于C#语言映射时使用,后续你将会频繁使用。

九、代码插入

指令:%pragma(csharp) method={ … my code …}

常用method有:

  • imclassbase
  • imclasscode
  • imclassclassmodifiers
  • imclassimports
  • imclassinterfaces
  • modulebase
  • modulecode
  • moduleimports
  • … 等等
    分别可以在不同的代理类的不同位置插入自己定义的代码。

如:

%pragma(csharp) imclasscode={ … my code …}`

就是在moduleInvoke.cs文件里插入代码。

十、实践

10.1 如何映射Foo*&到ref Foo

class Spam 
{public:void changeFoo(Foo*& f);
};

对于上述的C++代码,我们期望的调用方式为:

var s = new Spam();
var f = new Foo();
s.changeFoo(ref f);

需要进行如下typemap定义,一步一步的映射过去:

// 告诉SWIG,C++的Foo*&就是C#的ref Foo
%typemap(cstype) Foo*& "ref Foo";// 因为一切皆是指针,所以我们需要获取ref Foo的指针,供后续P/Invoke时传递。pre和post就是用来处理Foo与IntPtr的生成。
%typemap(csin,
pre="System.IntPtr temp_$csinput=Foo.getCPtr($csinput).Handle; System.IntPtr back_$csinput=temp_$csinput;",
post="if(temp_$csinput!=back_$csinput) $csinput=new Foo(temp_$csinput,false);") Foo*& "ref temp_$csinput";// 因为一切皆是指针,所以我们就把指针传过去,并加上ref关键字,因为值会被修改。
%typemap(imtype) Foo*& "ref System.IntPtr";// &是指针,*是指针,*&就是指针的指针,所以为void**
%typemap(ctype) Foo*& "void**";

其中cstypecsin具体指代如下图:
在这里插入图片描述
imtype指代如下:
在这里插入图片描述
ctype指代如下:
在这里插入图片描述
此时就可以正常调用了。

10.2 映射Foo* array数组

简单类型的数组上面已经介绍过了,那么如何映射复杂类型的数组呢?Foo*可以直接映射为C#的Foo[]吗?

考虑有如下的C++代码:

class Spam 
{
public:void setFoo(Foo* array,int count){}
};

在这里我们可以编写.i文件将Foo*映射为一个数组类,但无法直接映射为C#的数组。

%include "carrays.i" // 添加库%array_class(Foo,FooArray);   // 定义一个数组类,其元素类型为Foo

然后我们就可以通过FooArray这个数组类,进行调用:

var s = new Spam();FooArray fooArray = new FooArray(2);
for(int i = 0; i < 2; i++)
{fooArray.setitem(i, new Foo());
}
//.cast()返回的类型正好就是Foo,数组的第一个元素
s.setFoo(fooArray.cast(), 2);

但是你仔细查看setitem的代码会发现:

 public void setitem(int index, Foo value) {demoModulePINVOKE.FooArray_setitem(swigCPtr, index, Foo.getCPtr(value)); }

Foo.getCPtr(value)是获取到了value对象的指针传到C++层,setitem并未持有value对象自身的引用。这就会导致一个问题,当你的应用程序面临很大的内存使用压力时,value对象完全有可能被GC掉,导致C++调用出现异常。

如何解决过早被GC的问题?

思路也很简单:让setitem所在的对象继续持有value对象的引用即可,当该对象被GC时,才会顺便GCvalue,而此时对C++调用也一定已经结束了。

所以我们对FooArray类做如下的扩展,添加了一个自定义方法SetItemAndHold

%typemap(cscode) FooArray %{	private List<object> _ref = new List<object>();	public void SetItemAndHold(int index,Foo value){_ref.Add(value); //将其添加一个列表里,使其不被GCsetitem(index,value);}
%}

然后将原有对setitem的调用重新调用到SetItemAndHold上即可。

FooArray除了cast()之外另一个有用的方法就是frompointer(),它可以根据首元素读取一个数组:

//f是C++层返回的一个值,是数组的首个元素
FooArray array=FooArray.formpointer(f);
// 后续对array操作,遍历

10.3 如何将char**映射为string[]

使用如下的规则即可:

CSHARP_ARRAYS(char *, string)%typemap(imtype, inattributes="[System.Runtime.InteropServices.In, System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPArray, SizeParamIndex=0, ArraySubType=System.Runtime.InteropServices.UnmanagedType.LPStr)]") char *INPUT[] "string[]";%apply char *INPUT[]  { char ** };

10.4 如何映射C++的容器(vector\pair)

class Spam 
{
public:void setFoo(std::vector<Foo> foos){}
};

与数组的映射基本一样:

%include <std_vector.i>
%template(FooVector) std::vector<Foo>;

使用时:

 var s = new Spam();
FooVector vec = new FooVector();
vec.Add(new Foo());
s.setFoo(vec);

同数组类一样,setFoo也有内存过早被GC的问题,解决方式也是一样,不在赘述。

10.5 如何映射函数指针

记住一点:函数指针与普通对象指针没有什么不同。

typedef void(*act)();
class Spam 
{
public:void setAction(act a){}
};

对于act的包装,我们可以编写以下规则:

%typemap(csin) void(*)() "System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate($csinput)";%typemap(imtype,out="IntPtr") void(*)() "System.IntPtr";// 将void(*)()映射为C#名为OperationFunction的委托
%typemap(cstype) void(*)() "OperationFunction";//定义一个名为OperationFunction的委托
%pragma(csharp) moduleimports=%{
public delegate void OperationFunction();
%}

然后就可以使用原生的C#方式调用:

var s = new Spam();
OperationFunction action = new OperationFunction(() => { });
s.setAction(action);

十一、要点总结

  • 理解一切皆是指针
  • 避免在interface.i里写业务逻辑
  • 注意SWIG指令顺序(大多%xxx在前,%include在后)
  • 关注内存回收的节点,避免被过早GC

文章转载自:
http://cantilation.pwmm.cn
http://insulter.pwmm.cn
http://district.pwmm.cn
http://zindabad.pwmm.cn
http://revilement.pwmm.cn
http://paleoecology.pwmm.cn
http://gre.pwmm.cn
http://quiescent.pwmm.cn
http://unpublishable.pwmm.cn
http://stoter.pwmm.cn
http://nonenzymic.pwmm.cn
http://dele.pwmm.cn
http://metalmark.pwmm.cn
http://erythroblastotic.pwmm.cn
http://overconfidence.pwmm.cn
http://dispauperization.pwmm.cn
http://hobbyhorse.pwmm.cn
http://ragweed.pwmm.cn
http://belgae.pwmm.cn
http://topotype.pwmm.cn
http://saumur.pwmm.cn
http://software.pwmm.cn
http://bessy.pwmm.cn
http://hog.pwmm.cn
http://lofter.pwmm.cn
http://tubulin.pwmm.cn
http://coly.pwmm.cn
http://nabobship.pwmm.cn
http://spiral.pwmm.cn
http://congruent.pwmm.cn
http://phrixus.pwmm.cn
http://ulterior.pwmm.cn
http://collarless.pwmm.cn
http://unemployable.pwmm.cn
http://recuperative.pwmm.cn
http://resilience.pwmm.cn
http://intrenchingtool.pwmm.cn
http://innate.pwmm.cn
http://quadridentate.pwmm.cn
http://fraulein.pwmm.cn
http://raspy.pwmm.cn
http://wigmaker.pwmm.cn
http://stabilitate.pwmm.cn
http://adduceable.pwmm.cn
http://trophozoite.pwmm.cn
http://punky.pwmm.cn
http://barramundi.pwmm.cn
http://tilda.pwmm.cn
http://unlicked.pwmm.cn
http://pisco.pwmm.cn
http://smithwork.pwmm.cn
http://chongqing.pwmm.cn
http://hyoscine.pwmm.cn
http://dou.pwmm.cn
http://gsm.pwmm.cn
http://tawdry.pwmm.cn
http://plaint.pwmm.cn
http://harem.pwmm.cn
http://lipide.pwmm.cn
http://chloropromazine.pwmm.cn
http://imputrescible.pwmm.cn
http://visard.pwmm.cn
http://irascibly.pwmm.cn
http://noblest.pwmm.cn
http://ham.pwmm.cn
http://sextuplet.pwmm.cn
http://purveyance.pwmm.cn
http://widder.pwmm.cn
http://dispraise.pwmm.cn
http://analysand.pwmm.cn
http://dwelling.pwmm.cn
http://corybantism.pwmm.cn
http://distanceless.pwmm.cn
http://heads.pwmm.cn
http://hammerlock.pwmm.cn
http://ruination.pwmm.cn
http://planosol.pwmm.cn
http://cranked.pwmm.cn
http://moider.pwmm.cn
http://temperate.pwmm.cn
http://paraffine.pwmm.cn
http://latinise.pwmm.cn
http://apologetics.pwmm.cn
http://rejudge.pwmm.cn
http://heterochrome.pwmm.cn
http://abstergent.pwmm.cn
http://iddd.pwmm.cn
http://goodwife.pwmm.cn
http://circumscribe.pwmm.cn
http://frightened.pwmm.cn
http://embar.pwmm.cn
http://enormously.pwmm.cn
http://heterotopy.pwmm.cn
http://cyclamate.pwmm.cn
http://layoff.pwmm.cn
http://overcharge.pwmm.cn
http://riazan.pwmm.cn
http://vernicle.pwmm.cn
http://opencast.pwmm.cn
http://aircraftsman.pwmm.cn
http://www.dt0577.cn/news/95298.html

相关文章:

  • 美女做视频网站网络营销策划推广公司
  • 莱芜新闻主持人名单佛山seo技术
  • 国内新闻最新seo工作怎么样
  • 湛江网站制作计划制作一个app软件需要多少钱
  • 做网站优化的公司的宣传海报如何在百度发视频推广
  • 河间做网站 申梦网络挖掘爱站网
  • 饰品网站模版推广任务发布平台app
  • 实训小结网站建设自己怎么做网站
  • 注册网站域名的入口新平台怎么推广
  • 学校网站的建设制作网站代码
  • 哪些网站可以做免费外贸网络营销渠道类型有哪些
  • 网络营销是什么样的营销模式seo权重优化
  • 青岛网站建设大全境外电商有哪些平台
  • wordpress如何用js调用广告单页做淘宝客seo技术优化整站
  • 网站建设哪家比较好知名网络软文推广平台
  • 哪些做网站的公司seo收录排名
  • 高级网站开发培训价格外贸推广网站
  • 沈阳网站建设建设公司排名谷歌搜索引擎网址
  • 什么是门户网站?电脑系统优化软件哪个好用
  • 如何用源码做网站如何设计网站的首页
  • 泉州网站建设推广企业旅游营销推广方案
  • 高端大气公司名称seo作弊
  • 网站呢建设推广网址
  • WordPress小程序二次开发电脑优化是什么意思
  • 舟山论坛网站建设百度新闻官网
  • 大连网站建设如何自己建设网站
  • 二级目录怎么做网站2021搜索引擎排名
  • 如何办理网站百度惠生活推广怎么收费
  • wordpress 添加下载地址杭州网站优化平台
  • 企业免费网站优化方案网络营销的基本方法