频道栏目
首页 > 资讯 > C++ > 正文

SWIG入门3: C/C++初级特性

12-08-13        来源:[db:作者]  
收藏   我要投稿

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 { 

19     PrintArray(a,sizeof(a)/sizeof(int)); 

20 } 

21   

22 void pb() 

23 { 

24     PrintArray(b,sizeof(b)/sizeof(int)); 

25 }
01 //file: ary.i 

02 %module ary 

03 %{ 

04   

05 extern int a[5]; 

06 extern int b[6]; 

07   

08 extern void pa(); 

09 extern void pb(); 

10 %} 

11   

12 int a[5]; 

13 int b[6]; 

14 void pa(); 

15 void pb();


01 #file: testary.py 

02 import ary 

03 print "a is:"

04 ary.pa() 

05 print str(ary.cvar.a) 

06 print "b is:"

07 print str(ary.cvar.b) 

08 ary.pb() 

09   

10 print "\n"

11 ary.cvar.a=ary.cvar.b 

12   

13 print "After a=b"

14 print "a is:"

15 ary.pa() 

16 print str(ary.cvar.a) 

17 print "b is:"

18 print str(ary.cvar.b) 

19 ary.pb()

运行结果:

view sourceprint?01 a is: 

02 {1,2,3,4,5,} 

03 _306720b7_p_int 

04 b is: 

05 _446720b7_p_int 

06 {10,20,30,40,50,60,} 

07   

08   

09 After a=b 

10 a is: www.2cto.com

11 {10,20,30,40,50,} 

12 _306720b7_p_int 

13 b is: 

14 _446720b7_p_int 

15 {10,20,30,40,50,60,}

可以看到,运行a=b并没有改变a指针指向的位置,而只是将b数组的前5个元素拷贝到a指针指向的位置而已。

相关TAG标签
上一篇:C# / .net 时间格式转换
下一篇:Ruby/Tk - grid网格几何管理器
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站