プログラミングなど

2009年10月18日日曜日

python ctypes

Python の ctypes モジュールについて調べてみた。

下記のような dll を作成して、ctypes モジュールで引数、戻り値の設定の仕方をどのようにしたらよいか調査した。
---- ctypes_test.dll ----

extern "C" {
__declspec(dllexport) int plus(int, int);
__declspec(dllexport) void plus_pointer(int*, int*, int*);
__declspec(dllexport) int* alloc_int();
__declspec(dllexport) void free_int(int*);
__declspec(dllexport) int set_calc_func(int (*)(int, int));
};
int plus(int lhs, int rhs) {
 return lhs + rhs;
}
void plus_pointer(int* pLhs, int* pRhs, int* pResult) {
 *pResult = *pLhs + *pRhs;
}
int* alloc_int() {
 int* p = new int(10);
 std::cout << "new :" << p << std::endl;;
 return p;
}
void free_int(int* p) {
 std::cout << "delete :" << p << std::endl;;
 delete p;
}
int set_calc_func(int (*func)(int, int)) {
 return func(100, 25);
}


---- python側 ----

# -*- coding: utf-8 -*-

from ctypes import *
test = cdll.LoadLibrary('ctypes_test.dll')

# ---- 単純な足し算1 ----
result = test.plus(10, 20)
print result # ok 30
# 整数と文字列は気にせず利用することができるよう工夫されているそうな

# ---- 単純な足し算2 ----
lhs = c_int(32)
rhs = c_int(41)
result = test.plus(lhs, rhs)
print result # ok 73

# ---- アドレス渡し ----
lhs = c_int(15)
rhs = c_int(25)
result = c_int(0)
test.plus_pointer(byref(lhs), byref(rhs), byref(result))
print result # ok c_long(40)
print result.value # ok 40

# ---- ポインタ渡し ----
lhs = c_int(21)
rhs = c_int(47)
result = c_int(0)
test.plus_pointer(pointer(lhs), pointer(rhs), pointer(result))
print result # ok c_long(68)
print result.value # ok 68

# ---- ポインタ取得 ----

# "デフォルトでは、関数は C int を返すと仮定されます。
# 他の戻り値の型を指定するには、関数オブジェクトの restype 属性に設定します。"
# とのこと。
alloc_func = test.alloc_int
alloc_func.restype = POINTER(c_int) # 戻り値が int* 型であることを指定
ptr = alloc_func() # ok new
print ptr.contents # ok c_long 10
print ptr.contents.value # ok 10
test.free_int(ptr) # ok delete (new の場合と同じアドレスをdeleteしているのでok)

# ---- 関数ポインタ ----
def plus(i, j):
  return i + j
def minus(i, j):
  return i - j
FuncType = CFUNCTYPE(c_int, c_int, c_int)
plus_func = FuncType(plus)
result = test.set_calc_func(plus_func)
print result # ok c_long(125)
minus_func = FuncType(minus)
result = test.set_calc_func(minus_func)
print result # ok c_long(75)

# End of file


================================

大体、必要なことは、できそう。