通常、使用する各関数にはctypes
引数と戻り値の型が宣言されている必要があります。これにより、Python は正しい数と型の引数をチェックし、Python オブジェクトの引数を正しい C データ オブジェクトに変換できます。残念ながら、この場合、 の通常の戻り値はにfunc
なりますc_char_p
が、生の C ポインター値へのアクセスを失い、戻り値を Python 文字列にctypes
変換しようとします。c_char_p
代わりに、戻り値の型を as として宣言し、文字列値を取得するためにPOINTER(c_char)
使用できcast
ます。これにより、戻り値はLP_c_char
解放可能なオブジェクトのままになります。
これが例です。デフォルトの戻り値の型は(32 ビット) であり、64 ビットのポインターは切り捨てられる可能性がある.restype
ため、64 ビットの Python では正しいと宣言することが特に重要であることに注意してください。c_int
このコードは、32 ビットと 64 ビットの両方のビルドでテストされています。
test.c
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API char* func(const char* str1, const char* str2) {
size_t len = strlen(str1) + strlen(str2) + 1;
char* tmp = malloc(len);
strcpy_s(tmp, len, str1);
strcat_s(tmp, len, str2);
return tmp;
}
API void freeMem(void *mem) {
free(mem);
}
test.py
import ctypes as ct
dll = ct.CDLL('./test')
dll.func.argtypes = ct.c_char_p,ct.c_char_p
dll.func.restype = ct.POINTER(ct.c_char)
dll.freeMem.argtypes = ct.c_void_p,
dll.freeMem.restype = None
# Helper function to extract the return value as a Python object
# and always free the pointer.
def freeMem(a,b):
p = dll.func(b'abcdef', b'ghijkl')
print(p)
s = ct.cast(p, ct.c_char_p).value
dll.freeMem(p)
return s
print(freeMem(b'abcdef', b'ghijkl'))
出力:
<ctypes.LP_c_char object at 0x00000279D7959DC0>
b'abcdefghijkl'