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;
}