SWIG入門3:C/C++初級特性

6043 ワード

SWIGというプロジェクトが確立された理由は、簡潔で自然なスクリプト言語インタフェースを提供するためであることがよく知られています.簡潔で自然なものとは何でしょうか.C/C++の関数はpythonの関数に直接カプセル化され、classはpythonのclassにカプセル化されるという意味です.これでみんなが使うとねじれません.以下、SWIGがサポートする初級C/C++の特性について説明します.
1関数
関数はコード多重化のソースです.SWIGは関数のカプセル化の道を簡略化する.パッケージが完了したらpythonで直接モジュールのメソッドとして呼び出されます.
%module example
int fact(int n);
>>> import example
>>> print example.fact(4)
24
>>>

2グローバル変数
c言語の様々なタイプの変数はpythonで使用できます.グローバル変数はモジュールのcvarという変数に格納されます.
//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.
" "barfloat %f
" "bardouble %f
" "barshort %hd
" "barlong %ld
" "barlonglong %lld
" "barunsigned %u
" ,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でいいです.たとえば
[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を投げます.
>>> 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を使用することである.この2つのキーワードは、読み取り専用変数と書き込み可能変数をそれぞれ表します.
%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はポインタを1つのオブジェクトに処理しただけです.
%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
",f) 1 >>> foo.fclose(f) 0

5配列
PYTHONには配列がありません.したがって,SWIGは配列のヘッダアドレスを1つのポインタとして一度だけカプセル化することができる.つまり、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("}
"); } 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 "
" 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