Python使用ctypes访问C代码
工具:CodeBlocks
新建一个分享库工程( Shared library ),随便编写一个C代码的函数
// test.c #include <stdio.h> int fib(int n) { if( n == 0 || n == 1) { return 1; } else { return fib(n-1) + fib(n-2); } }
编译,在bin/Debug/目录中生成libtest.dll动态链接库文件,该文件可以通过ctypes模块进行访问使用,在该文件目录下新建一个test.py文件
# test.py import ctypes import os _file_path = os.path.join(os.path.dirname(__file__), 'libtest.dll') _mod = ctypes.cdll.LoadLibrary(_file_path) #加载动态库文件,返回一个类对象 <class 'ctypes.CDLL'> # int fib(int n) fib = _mod.fib #获取类方法 fib.argtypes = (ctype_int,) #配置参数类型(tuple) fib.restype = ctypes_int #配置返回值类型 #现在可以直接使用fib函数了 for i in range(10): print( fib(i), end=' ' )
C函数的指针作为参数情况
// 参数有指针的函数 int divide(int a, int b, int *remainder) { int quot = a / b; *remainder = a % b; return quot; }
# 相应的处理办法 # int divide(int, int, int *) _divide = _mod.divide _divide.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int)) _divide.restype = ctypes.c_int def divide(x, y): rem = ctypes.c_int() quot = _divide(x, y, rem) return quot,rem.value
C函数的数组作参数的情况
double avg(double *a, int n) { int i; double total = 0.0; for (i = 0; i < n; i++) { total += a[i]; } return total / n;
# 对于C中的数组,Python中没有固定的对应类型,所以要分类处理:
# Define a special type for the 'double *' argument class DoubleArrayType: def from_param(self, param): #对传进来的参数进行分发 typename = type(param).__name__ if hasattr(self, 'from_' + typename): return getattr(self, 'from_' + typename)(param) elif isinstance(param, ctypes.Array): return param else: raise TypeError("Can't convert %s" % typename) # Cast from array.array objects def from_array(self, param): if param.typecode != 'd': raise TypeError('must be an array of doubles') ptr, _ = param.buffer_info() return ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double)) # Cast from lists/tuples def from_list(self, param): val = ((ctypes.c_double)*len(param))(*param) return val from_tuple = from_list # Cast from a numpy array def from_ndarray(self, param): return param.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) DoubleArray = DoubleArrayType() _avg = _mod.avg _avg.argtypes = (DoubleArray, ctypes.c_int) _avg.restype = ctypes.c_double def avg(values): return _avg(values, len(values))
KEEP LEARNING!