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