python⇔Cのインターフェイスに関するメモ
pythonて言語には元からCでのAPIがあるのですが、いちいちpythonの中のオブジェクトとCでの変数とをやり取りする際に型の変換が必要になります。pythonの世界では全ての変数がオブジェクトなので仕方ないのですが・・・。そこで、ctypesというモジュールを使うことで、ある程度簡単にこの変数の型変換を行えるようになります。pythonからCのDLLを呼んだり、pythonからCの関数をcallしたりする際には重宝しそうです。
以下、簡単なサンプルです。
まず、python側のコード
import ctypes # DLLをロード lib = ctypes.cdll.LoadLibrary("CalcDll.dll") # 関数呼び出し print lib.fnCalcDll(None) # 配列渡し TenIntegers = ctypes.c_int * 10 ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) print lib.fnCalcArray(10, ii) # 構造体渡し class _DATA(ctypes.Structure): _fields_ = [("ric", ctypes.c_char_p), ("fid", ctypes.c_char_p), ("value", ctypes.c_int)] data = _DATA("RIC", "FID", 50) data2 = lib.fnCalcRic(ctypes.byref(data)) ret = _DATA.from_address(data2) print ret.value
そして、呼び出されるCのコード(VC++7.1でコンパイルしたものです)
CalcDll.h
#ifdef CALCDLL_EXPORTS #define CALCDLL_API __declspec(dllexport) #else #define CALCDLL_API __declspec(dllimport) #endif extern "C" { CALCDLL_API int fnCalcDll(void); CALCDLL_API int fnCalcArray(int size, int array[]); typedef struct { char* ric_; char* fid_; int value_; } ric_data; CALCDLL_API ric_data* fnCalcRic(ric_data* data); }
CalcDll.cpp
#include "CalcDll.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } CALCDLL_API int fnCalcDll(void) { return 42; } CALCDLL_API int fnCalcArray(int size, int array[]) { int sum = 0; for (int i = 0; i < size; ++i) { sum += array[i]; } return sum; } CALCDLL_API ric_data* fnCalcRic(ric_data* data) { data->value_ *= 2; return data; }