目录
简要说明
ctypes
是Python的外部函数库。它提供C兼容的数据类型,并允许在DLL或共享库中调用函数,它可以用于在纯Python中包装这些库。cdll 加载使用标准cdecl
调用约定导出函数的库,而windll库使用stdcall
调用约定调用函数。调用形式如下:
from ctypes import *
clib = windll.LoadLibrary("C:\\Users\\ad\\Desktop\\python_test\\Python_visa_test\\XXX.dll")
开发环境
操作系统:window7
python版本:3.4.4
编辑器:vscode,作为一款跨平台轻量级的编辑器,完全可以替代vs,推荐大家使用
封装数据结构
对于C语言中经常用到的数组、结构体、指针、枚举等类型,ctypes模块都提供了封装。ctypes定义了许多原始的C兼容数据类型,如下:
数组
#char型的一位数组,长度为8
x = c_char * 8
#int型的一位数组,长度为8
y= c_int * 8
#int型的二维数组(等同于c语言: int z[8][256])
z = y*256
结构体
ctypes中将结构体封装成类,需要继承Structure,在_fields_中定义成员,如下:
class DeviceInfo(Structure):
x= c_char * 8
y = c_char * 8
z= c_char * 8
_fields_ = [("x1",x* 256), #二维数组
("y1",y* 256),
("z1",z* 256),
("n",c_int * 8),
("m",c_int),
("a",c_int),
("b",c_char * 8 )]
指针
通过pointer在ctypes类型上调用函数 来创建指针实例:
from ctypes import * i = c_int(42) pi = pointer(i)
指针实例有一个contents
属性,它返回指针指向的i
对象,上面的对象:
>>> pi.contents c_long(42) >>>
注意,ctypes
没有OOR(原始对象返回),每次检索属性时它都会构造一个新的等效对象 :
>>> pi.contents is i False >>> pi.contents is pi.contents False >>>
将另一个c_int
实例分配给指针的contents属性会导致指针指向存储它的内存位置:
>>> i = c_int(99) >>> pi.contents = i >>> pi.contents c_long(99) >>>
该pointer()
函数不仅仅是创建指针实例,还必须首先创建指针类型。这是通过POINTER()
接受任何ctypes
类型的函数完成的 ,并返回一个新类型 :
>>> PI = POINTER(c_int) >>> PI <class 'ctypes.LP_c_long'> >>> PI(42) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: expected c_long instead of int >>> PI(c_int(42)) <ctypes.LP_c_long object at 0x...> >>>
调用不带参数的指针类型会创建一个NULL
指针。 NULL
指针有一个False
布尔值:
>>> null_ptr = POINTER(c_int)() >>> print(bool(null_ptr)) False >>>
ctypes
检查NULL
何时解除引用指针(但解除引用无效的非NULL
指针会使Python崩溃):
>>> null_ptr[0] Traceback (most recent call last): .... ValueError: NULL pointer access >>> >>> null_ptr[0] = 1234 Traceback (most recent call last): .... ValueError: NULL pointer access >>>
枚举
枚举需要继承Enum,如下:
from enum import Enum
class Cand(Enum):
x= 0
y= 1
函数传递结构体参数
C库中有这样一个函数:
int getDevInfo(DeviceInfo *info,int counter,char *callBack);
在ctypes中传递结构体,只能传递结构体指针,不能传递实例对象,并且调用C库中的函数参数必须以ctypes基本数据类型封装才能调用,如下:
#调用C库函数
getDevInfo = clib .getDevInfo
#告诉ctypes数据类型
getDevInfo .argtypes= [POINTER(DeviceInfo ),c_int,POINTER(c_char)]
t_callBack = c_char()
#创建一个结构体实例
t_devInfo = AllDeviceInfo()
ret = getDevInfo (byref(t_devInfo ),c_int(3),byref(t_callBack))
if(ret < 0):
print("CALL FAILED!")
else:
print("CALL SUCCESS!")
备注
在这里只介绍了一些ctypes模块常用的地方,感兴趣的同学,可以参照官方教程:https://docs.python.org/3.5/library/ctypes.html#