众所周知,SWIG这个项目创建的缘由,是为你们提供简洁而又天然的脚本语言接口。什么是简洁而天然呢?它的意思就是C/C++的函数就直接被封装为python的函数,class就被封装成python的class。 这样你们用起来就不会变扭。下面讲一讲一些SWIG所支持的初级的C/C++特性。python
1 函数linux
函数乃是代码复用之源。SWIG对于函数的封装之道至简。封装完以后在python里直接做为模块的方法调用。数组
%module example int fact(int n);
>>> import example >>> print example.fact(4) 24 >>>
2 全局变量函数
c语言中的各类类型的变量在python中均可以使用。全局变量被放在模块的cvar这个变量中。this
//file: foo.c #include <stdio.h> int bar = 2; float barfloat = 3.14; double bardouble=3.1415926; short barshort=10000; long barlong=200; long long barlonglong=2000000000000ll; unsigned barunsigned = 200; int barFunc() { printf("this is bar %d.\n" "barfloat %f\n" "bardouble %f\n" "barshort %hd\n" "barlong %ld\n" "barlonglong %lld\n" "barunsigned %u\n" ,bar,barfloat, bardouble,barshort, barlong,barlonglong, barunsigned); return 0; }
//file: foo.i %module foo %{ extern int bar; extern float barfloat; extern double bardouble; extern short barshort; extern long barlong; extern long long barlonglong; extern unsigned barunsigned; %} int bar; float barfloat; double bardouble; short barshort; long barlong; long long barlonglong; unsigned barunsigned; int barFunc();
须要注意的是,全局变量必需在.i文件中extern一下。不然编译foo_wrap.c的时候会报错。指针
使用的时候直接使用foo.var.xxx就能够了。好比code
[GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> foo.bar Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'bar' >>> print foo.cvar.bar 2
特别值得注意的是, 每个类型的数字在python中也会作范围检查,若是赋值超过了该类型的范围,python会抛overflowerror.orm
>>> foo.cvar.barunsigned=-1 Traceback (most recent call last): File "<stdin>", line 1, in <module> OverflowError: in variable 'barunsigned' of type 'unsigned int'
另外,假如修改一个const全局变量,会引起一个segment fault。 因此处理const全局变量的最好方法是使用%immutable 和%mutable。 这两个关键字分别表明只读和可写的变量。对象
%immutable; int barconst;
[GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> foo.cvar.barconst=2 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: Variable barconst is read-only. >>>
这样作只会引起异常,而不会引起更致命的段错误。 %immutable指令会一直有效,直到你显示的使用%mutable指令为止。接口
假如你以为cvar这个名字不够酷,你也能够为他换一个别的名字。只要在执行swig时候使用-globals varname 参数。
swig -python -globals variable foo.i
3 SWIG的const变量和枚举变量
除了直接使用C语言模块中定义的变量,在SWIG脚本中,也能够为python脚本定义的const变量和枚举变量。能够用到的技术有#define, enum,%constant。 其中enum枚举变量须要也写进你的xxx_wrap.c代码中去。
%{ enum People{Man,Woman}; %} #define PI 3.1415 #define VERSION "1.0" enum People{Man,Woman}; %constant int barconstant=100;
使用这种变量就不须要经过cvar了。由于这就是Python脚本自身定义的变量,和你的C语言的代码无关。
Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> foo.VERSION '1.0' >>> foo.PI 3.1415000000000002 >>> foo.Woman 1 >>> foo.Man 0 >>> foo.barconstant 100
4 指针
由于PYTHON里面并无指针,因此SWIG只是将指针处理成了一种对象。
%module foo FILE* fopen(const char* fname,const char* mode); int fputs(const char*,FILE*); int fclose(FILE*);
咱们能够直接将库函数封装起来使用。
[GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> foo.fopen("test","w") <Swig Object of type 'FILE *' at 0xb741c620> >>> f=foo.fopen("test","w") >>> foo.fputs("1234\n",f) 1 >>> foo.fclose(f) 0
5 数组
PYTHON里没有数组。所以SWIG只能将数组的首地址做为一个指针进行一次封装。也就是说,在PYTHON中,你只能把这个数组当成指针来用。它能够被传递给参数为指针的函数做为参数。也能够被另外一个数组进行赋值,实际上赋值进行的就是内存拷贝,而并不会改变指针的地址。能够看下面的例子。
//file: ary.c #include <stdio.h> int a[5]={1,2,3,4,5}; int b[6]={10,20,30,40,50,60}; void PrintArray(int *a,size_t n) { size_t i=0; printf("{"); for(i=0;i<n;i++) { printf("%d,",*a++); } printf("}\n"); } void pa() { PrintArray(a,sizeof(a)/sizeof(int)); } void pb() { PrintArray(b,sizeof(b)/sizeof(int)); }
//file: ary.i %module ary %{ extern int a[5]; extern int b[6]; extern void pa(); extern void pb(); %} int a[5]; int b[6]; void pa(); void pb();
#file: testary.py import ary print "a is:" ary.pa() print str(ary.cvar.a) print "b is:" print str(ary.cvar.b) ary.pb() print "\n" ary.cvar.a=ary.cvar.b print "After a=b" print "a is:" ary.pa() print str(ary.cvar.a) print "b is:" print str(ary.cvar.b) ary.pb()
运行结果:
a is: {1,2,3,4,5,} _306720b7_p_int b is: _446720b7_p_int {10,20,30,40,50,60,} After a=b a is: {10,20,30,40,50,} _306720b7_p_int b is: _446720b7_p_int {10,20,30,40,50,60,}
能够看到,运行a=b并无改变a指针指向的位置,而只是将b数组的前5个元素拷贝到a指针指向的位置而已。
你能够在此处下载本文中的例子 https://dl.dropbox.com/u/35106490/swig3.tgz