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

众所周知,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
相关文章
相关标签/搜索