- ctypes 是 python 内建的模块,可以实现 python 直接调用动态链接库
- 提供了一套数据类型,实现 C 类型到 python的映射
- 对C++支持较差,特别是复杂类型
- 当手头只有第三方动态链接库时,ctypes 比较方便(否则建议用SWIG包装)
使用方法
1)加载DLL
from ctypes import *
# 针对 WinDLL 类的对象
objdll = windll.LoadLibrary(dllpath)
objdll = WinDLL(dllpath)
# 针对 CDLL 类的对象
objdll = cdll.LoadLibrary(dllpath)
objdll = CDLL(dllpath)
2)声明函数的输入和输出类型
# argtypes 声明输入类型
objdll.my_func.argtypes = [c_char_p, c_int, c_double]
# restype 声明输出类型
# 默认返回 c_int 类型
objdll.my_func.restype = c_char_p
3)函数调用
res = objdll.my_func(...)
语法细节
1)基本 C 类型的映射
完整表格见官方文档
C type | Python type | ctypes type |
---|---|---|
Bool | bool | c_bool |
char | string | c_char |
wchar_t | unicode string | c_wchar |
int | int/long | c_int |
float | float | c_float |
double | float | c_double |
char* | string/None | c_char_p |
void* | int/long/None | c_void_p |
2)数组
# 整形数组
type_int_array_10 = c_int * 10
my_array = type_int_array_10()
my_array[2] = c_int(5)
3)类型指针和引用
# 使用 POINTER
type_p_int = POINTER(c_int)
v_int = c_int(4)
p_int = type_p_int(v_int)
# 或者使用 pointer (相当于 & )
p_int = pointer(v_int)
# 使用 contents 获取指针指向的对象(相当于 * )
p_int.contents
p_int[0]
# 使用 byref 传递引用参数
f_value = c_float(2)
objdll.func(byref(f_value))
4)函数指针
# 函数原型
int compar(const int*, const int*)
# 使用 CFUNCTYPE 创建 ctypes 的函数指针类型
CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
# 定义一个 python 下的函数
def py_cmp_func(a, b):
return a[0]-b[0]
# 获得对应 C 函数的函数指针
p_c_cmp_func = CMPFUNC(py_cmp_func)
5)结构体、联合体类型
ctypes 里定义了 Structure 和 Union 基础类,必须对其做继承,并用 fields 定义属性
from ctypes import *
class Test1(Structure):
_fields_ = [('x', c_int),
('y', c_char)]
test1 = Test1(1,2)
# 包含指向结构体指针的情况
class Test2(Structure):
pass
Test2._fields_ = [('x', c_int),
('y', c_char),
('next', POINTER(Test2))]