HOME | ドキュメント |  ブログ  |  BBS  |  瓦版  | 将棋プロジェクト |  物置小屋   

JavaScriptで将棋盤 象歩ブログ ねんきん特別便
04 May 2008

PythonからC++クラスを呼び出す(2)

Python  

今回は Python の ctypes モジュールを使い C++ クラスを Python から呼び出してみました。 ctypes モジュールは python2.5 以降では標準で含まれるようです。 まずは C++ クラスのコンストラクタ、デストラクタ、メンバ関数の wrapper 関数を作り、 Python から呼び出してみました。

題材は昨今作成中の詰将棋プログラムです。 以下のサンプル出力では、 まず共有ライブラリ libcshogi.so をロードし、 次にコンストラクタに盤面情報を文字列で渡し、 最後に探索メソッドを呼び出し、解答を出力しています。 ctypes は使い易い。Python 標準実装と云うのも心強いし、 とりあえず決まりかな^^

$ python2.5
>>> import ctypes
>>> so=ctypes.CDLL("./libcshogi.so")
>>> cp=so.cshogi_create('K32S22S34L11P13P23P44~R2BG3S2N4L3Pe/P54b53p41~G/')
 9 8 7 6 5 4 3 2 1
|.|.|.|.|.|p|.|.|L|1 {R2,B,G3,S2,N4,L3,Pe}
|.|.|.|.|.|.|K|S|.|2
|.|.|.|.|b|.|.|P|P|3
|.|.|.|.|P|P|S|.|.|4
|.|.|.|.|.|.|.|.|.|5
|.|.|.|.|.|.|.|.|.|6
|.|.|.|.|.|.|.|.|.|7
|.|.|.|.|.|.|.|.|.|8
|.|.|.|.|.|.|.|.|.|9 {G}

>>> so.cshogi_solve(cp, 7)
G33 K2132 b3153 S3122 p3141 K3121 S32
G33 K2132 b3153 S3122 p3141 K1221 S21


以下の説明では話を簡単にするため、次のような C++ クラス CShogi を考えます。 (実際のファイルは CShogi.h と CShogi.cpp)

#include <cstring>
class CShogi {
private:
    char buf[512];
public:
    CShogi() {
        printf("CShogi:: (new)\n");
    }
    ~CShogi() {
        printf("CShogi:: (del)\n");
    }
    void puts(const char* p) {
        printf("CShogi::puts (%s)\n", p);
        strcpy(buf, p);
    }
    const char* gets() const {
        printf("CShogi::gets (%s)\n", buf);
        return buf;
    }
};

まず wrapper 関数を作ります。ソース cshogi.cpp は以下の通り。

#include "cshogi.h"
#include "CShogi.h"
void* cshogi_create() {
    return (void*) new CShogi;
}
void cshogi_delete(void* p) {
    delete (CShogi*)p;
}
void cshogi_puts(void* p, const char* s) {
    ((CShogi*)p)->puts(s);
}
const char* cshogi_gets(void* p) {
    return ((CShogi*)p)->gets();
}

ヘッダファイル cshogi.h は C からも呼び出せる形式にします。 次のようになります。

#ifdef __cplusplus
extern "C" {
#endif
    void* cshogi_create(void);
    void cshogi_delete(void*);
    void cshogi_puts(void*, const char*);
    const char* cshogi_gets(void*);
#ifdef __cplusplus
}
#endif

次に共有ライブラリを作ります。 ビルドが正常終了したなら libcshogi.so がカレントディレクトリに出来てるはずです。

$ g++ -g -Wall -fPIC -o CShogi.o -c CShogi.cpp
$ g++ -g -Wall -fPIC -o cshogi.o -c cshogi.cpp
$ g++ -shared CShogi.o cshogi.o -o libcshogi.so

さて、Python から呼び出してみましょう。

$ python2.5
>>> import ctypes
>>> so = ctypes.CDLL("./libcshogi.so")
>>> cp = so.cshogi_create()
CShogi:: (new)
>>> so.cshogi_puts(cp, 'abc')
CShogi::puts (abc)
>>> so.cshogi_gets(cp)
>>> so.cshogi_gets.restype = ctypes.c_char_p
>>> so.cshogi_gets(cp)
CShogi::gets (abc)
'abc'
>>> so.cshogi_delete(cp)
CShogi:: del

最後に Python のクラスモジュール CShogi.py を作ります。 関数のプロトタイプ宣言が追加されています。 __del__ メソッドにはバッドノウハウを追加。

#! /usr/bin/python2.5
import ctypes
from ctypes import c_void_p, c_char_p
so=ctypes.CDLL("./libcshogi.so")

class CShogi(object):
    def __init__(self):
        so.cshogi_create.restype = c_void_p
        self.v = so.cshogi_create()
    def __del__(self, so=so):
        so.cshogi_delete.argtypes = [c_void_p]
        so.cshogi_delete(self.v)
    def puts(self, s):
        so.cshogi_puts.argtypes = [c_void_p, c_char_p]
        so.cshogi_puts(self.v, s)
    def gets(self):
        so.cshogi_gets.argtypes = [c_void_p]
        so.cshogi_gets.restype = c_char_p
        return so.cshogi_gets(self.v)

if __name__ == '__main__':
    ob = CShogi()
    ob.puts('abc')
    a = ob.gets()
    ob.puts('xyz')
    x = ob.gets()
    print 'a=', a, 'len=', len(a), 'type=', type(a)
    print 'x=', x, 'len=', len(x), 'type=', type(x)

これを実行した出力は以下の通りです。

$ python2.5 CShogi.py
CShogi:: (new)
CShogi::puts (abc)
CShogi::gets (abc)
CShogi::puts (xyz)
CShogi::gets (xyz)
a= abc len= 3 type= <type 'str'>
x= xyz len= 3 type= <type 'str'>
CShogi:: (del)

参考サイト

Comments
There is no comment.
Trackbacks

【注意】TrackBack 送信なさる場合、 あなたの記事中に参照リンク (当ブログの URL 記述) が必要です。 トラックバックスパム防止のため、御了承ください。

There is no trackback.
Post a comment











一回プレビューして投稿内容の確認をしてください。その後に投稿可能になります。