SWIG入門3:C/C++初級特性
SWIGというプロジェクトが確立された理由は、簡潔で自然なスクリプト言語インタフェースを提供するためであることがよく知られています.簡潔で自然なものとは何でしょうか.C/C++の関数はpythonの関数に直接カプセル化され、classはpythonのclassにカプセル化されるという意味です.これでみんなが使うとねじれません.以下、SWIGがサポートする初級C/C++の特性について説明します.
1関数
関数はコード多重化のソースです.SWIGは関数のカプセル化の道を簡略化する.パッケージが完了したらpythonで直接モジュールのメソッドとして呼び出されます.
2グローバル変数
c言語の様々なタイプの変数はpythonで使用できます.グローバル変数はモジュールのcvarという変数に格納されます.
グローバル変数は必須である.iファイルのexternをクリックします.そうでなければfoo_をコンパイルwrap.cの時に間違えます.
使用するときはfooをそのまま使用します.var.xxxでいいです.たとえば
特に、各タイプの数字はpythonでも範囲チェックを行い、そのタイプの範囲を超えるとpythonはoverflowerrorを投げます.
また、constグローバル変数を変更すると、segment faultが発生します.したがってconstグローバル変数を処理する最善の方法は%immutableと%mutableを使用することである.この2つのキーワードは、読み取り専用変数と書き込み可能変数をそれぞれ表します.
これは異常を引き起こすだけで、より致命的なセグメントエラーを引き起こすことはありません.%immutableコマンドは、%mutableコマンドを表示するまで有効です.
cvarという名前がクールではないと思ったら、彼のために別の名前を変えることもできます.swigを実行するときに-globals varnameパラメータを使用する限り.
3 SWIGのconst変数と列挙変数
C言語モジュールで定義された変数を直接使用するだけでなく、SWIGスクリプトでpythonスクリプトで定義されたconst変数と列挙変数も使用できます.使用できる技術は、#define,enum,%constantです.その中でenum列挙変数もあなたのxxxに書く必要があります.wrap.cコードから行きます.
この変数を使用するとcvarを通過する必要はありません.これがPythonスクリプト自体が定義した変数なので、あなたのC言語のコードとは関係ありません.
4ポインタ
PYTHONにはポインタが入っていないため、SWIGはポインタを1つのオブジェクトに処理しただけです.
ライブラリ関数を直接カプセル化して使用できます.
5配列
PYTHONには配列がありません.したがって,SWIGは配列のヘッダアドレスを1つのポインタとして一度だけカプセル化することができる.つまり、PYTHONでは、この配列をポインタとして使うしかありません.パラメータがポインタである関数にパラメータとして渡すことができます.ポインタのアドレスを変更せずにメモリコピーを行う別の配列で値を割り当てることもできます.次の例を見ることができます.
実行結果:
a=bを実行すると、aポインタが指す位置は変更されず、b配列の最初の5つの要素をaポインタが指す位置にコピーするだけであることがわかる.
ここで本明細書の例をダウンロードできますhttps://dl.dropbox.com/u/35106490/swig3.tgz
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