python使用ctypes调用C接口库
之前项目需要测试C接口函数,网上搜了下,python的ctypes模块还是挺好用的。现在有时间总结下
1. 科普
windows下调用C接口函数,一般是调用dll或lib库。dll是指动态链接库,lib是指静态库,一般来说调用动态库比较多。
ctypes提供了三种调用动态库的对象:cdll、windll、oledll。其中cdll主要用来加载C语言调用方式(cdecl),windll主要用来加载WIN32调用方式(stdcall),而oledll使用WIN32调用方式(stdcall)且返回值是Windows里返回的HRESULT值。从而实现在python代码中调用C函数的功能。是不是很神奇。
2. 使用ctypes
ctypes内置函数,不需要安装
from ctypes import * # 导入
CDLL('/usr/local/lib/libusb-1.0.so', mode=ctypes.RTLD_GLOBAL) # 加载.so动态库,mode=ctypes.RTLD_GLOBAL实现如果调用的动态库有其它依赖库时,提前加载的功能
libc = cdll.LoadLibrary('/opt/bin/lib/libqkey.so') # 例如,libqkey.so依赖了上述libusb-1.0.so库,就需要加载libusb-1.0.so库为全局加载
DeviceId = [0x00] * 8
DeviceId = (c_ubyte * 8)(*DeviceId) # 这个是之前比较傻的做法,因为要先给这个变量分配一段地址,其实这里用
libc.GenStartInfo(byref(DeviceId)) # 调用C语言接口函数 GenStartInfo
deviceId = ctypes.c_void_p()
DeviceId = ctypes.pointer(deviceId)
libc.GenStartInfo(DeviceId) # 使用指针即可
byref(n)返回的相当于C的指针右值&n,本身没有被分配空间
pointer返回的相当于指针左值T* p=&n,可以改变,可以取地址
这样就完成了最基本的调用C接口函数的功能
有时候希望打印出来,但如果返回值不对的时候,打印总是出错,于是写了一个打印函数
def return_value(arr):
if hasattr(arr,'value'):
return arr.value
else:
values = []
length = len(arr)
for i in range(length):
values.append(arr[i])
return values
这个写到一个类里面调用起来更方便