ctypes
是
Python
的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用C DLL中的函数。ctypes的官方文档在
这里
。
1. ctypes基本数据类型映射表
参数类型预先设定好,或者在调用函数时再把参数转成相应的c_***类型。ctypes的类型对应如下:
ctypes type
|
C type
|
Python Type
|
c_char
|
char
|
1-character string
|
c_wchar
|
wchar_t
|
1-character unicode string
|
c_byte
|
char
|
int/long
|
c_ubyte
|
unsigned char
|
int/long
|
c_bool
|
bool
|
bool
|
c_short
|
short
|
int/long
|
c_ushort
|
unsigned short
|
int/long
|
c_int
|
int
|
int/long
|
c_uint
|
unsigned int
|
int/long
|
c_long
|
long
|
int/long
|
c_ulong
|
unsigned long
|
int/long
|
c_longlong
|
__int64 or longlong
|
int/long
|
c_ulonglong
|
unsigned __int64 or unsigned long long
|
int/long
|
c_float
|
float
|
float
|
c_double
|
double
|
float
|
c_longdouble
|
long double float
|
float
|
c_char_p
|
char *
|
string or None
|
c_wchar_p
|
wchar_t *
|
unicode or None
|
c_void_p
|
void *
|
int/long or None
|
|
|
|
对应的指针类型是在后面加上"_p",如int*是c_int_p等等。在python中要实现c语言中的结构,需要用到类。
2. 加载DLL
访问dll,首先需引入ctypes库
from
ctypes
import
*
假设你已经有了一个的DLL(名字是add.dll),且该DLL有一个符合cdecl(这里强调调用约定是因为,stdcall调用约定和cdecl调用约定声明的导出函数,在使用python加载时使用的加载函数是不同的,后面会有说明)调用约定的导出函数Add。
stdcall调用约定:两种加载方式
[python]
view plain
-
Objdll = ctypes.cdll.LoadLibrary(
"dllpath"
)
-
Objdll = ctypes.CDLL(
"dllpath"
)
其实windll和cdll分别是WinDLL类和CDll类的对象。
linux下:
lib_nvr = cdll.LoadLibrary('./nvr.so')
2. python中声明c变量并给动态库传参数
(1)字符串:加 b
login_id = lib_nvr.Login(b'192.168.0.222', 37777, b'admin', b'Ehigh2014')
print ("login", login_id)
(2)c风格整型:
#定义一个c类型的变量
size =c_int() //定义一个 c 风格 int 变量
leaving = lib_nvr.GetData(c_char_p(buffer.ctypes.data), 1024*1024*10, pointer(size) )
pointer(size) // 取地址
(3)c风格数组:传递指针
# 测试get_data
buffer = numpy.zeros([1024*1024*10], dtype=numpy.uint8) //创建numpy数组
print ("..............")
for i in range(15):
print (buffer[ i ])
print ("done!")
#定义一个c类型的变量
size =c_int() //传递指针
leaving = lib_nvr.GetData(c_char_p(buffer.ctypes.data), 1024*1024*10, pointer(size) )
4. 指针与引用
常用的通过调用ctypes类型的指针函数来创建指针实例:
[python]
view plain
-
>>> p = create_string_buffer(
"Hello"
,
10
)
-
>>>
print
sizeof(p), repr(p.raw)
-
10
'Hello/x00/x00/x00/x00/x00'
不带参数的调用指针类型创建一个NULL指针, NULL指针有一个False布尔值
[python]
view plain
-
>>> null_ptr = POINTER(c_int)()
-
>>>
print
bool(null_ptr)
-
False
指针实例有一个contents属性,返回这个指针所指向的对象。
另外,byref()是用来传递引用参数,pointer()作为传参通常会创建一个实际的指针对象,当不需要实际指针对象时,则可使用byref()
5. 结构体类型处理
Structures和Unions必须继承Structure和Union基础类,它们都在ctypes模块中定义,每一个子类必须定义个_fields_属性,_fields_是一个二维的tuples列表,包含着每个field的name及type,这field类型必须是一个ctypes类型,如c_int,或者任何其他的继承ctypes的类型,如Structure, Union, Array, 指针等。
例如有一个简单结构,包含两个整型x和y,可如下初始化一个结构:
[python]
view plain
-
from
ctypes
import
*
-
import
types
-
class
Test(Structure):
-
_fields_ = [(
'x'
, c_int),
-
(
'y'
, c_char)]
-
test1 = Test(
1
,
2
)
另外,如结构体用于链表操作,即包含指向结构体指针时,若直接定义:
[python]
view plain
-
from
ctypes
import
*
-
import
types
-
class
Test(Structure):
-
_fields_ = [(
'x'
, c_int),
-
(
'y'
, c_char),
-
(
'next'
, Test)]
则python会报错type未定义,:
[python]
view plain
-
from
ctypes
import
*
-
import
types
-
class
Test(Structure):
-
pass
-
Test._fields_ = [(
'x'
, c_int),
-
(
'y'
, c_char),
-
(
'next'
, POINTER(Test))]
6. 数组定义
数组包含一个固定数目的相同类型的实例,常用创建数组类型是对一个数据类型与一个正数相乘,例如:
[python]
view plain
-
初始化和使用数组:
-
-
<span style=
"color:#0000ff;"
>>>>
from
ctypes
import
*
-
>>> TenIntegers = c_int *
10
-
>>> ii = TenIntegers(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
)
-
>>>
print
ii
-
<c_long_Array_10 object at
0x
...>
-
>>>
for
i
in
ii:
print
i,
-
</span>
7. 回调函数
ctypes可以从python可调用对象中创建一个c可调用的函数指针,这些通常被称为回调函数。
(这个等用到时,再仔细研究。。。)
8. 一个例子
c函数代码如下
typedef struct
unsigned long DeviceType;
int Handle;
int NumberOfClients;
int SerialNumber;
int MaxAllowedClients;
}NeoDevice;
int _stdcall icsneoFindNeoDevices(unsigned long DeviceTypes, NeoDevice *pNeoDevices, int *pNumberOfDevices);
python使用如下
class NeoDevice(Structure):
_fields_ = [("DeviceType",c_ulong),
("Handle",c_int),
("NumberOfClients",c_int),
("SerialNumber",c_int),
("MaxAllowedClients",c_int)]
class cNeoVICan(CCanBase):
def __init__(self):
neoVi = windll.icsneo40
self.icsneoFindNeoDevices = neoVi.icsneoFindNeoDevices
if __name__ == "__main__":
canBus = cNeoVICan()
print canBus.icsneoGetDLLVersion()
iNumberOfDevices = (NeoDevice * 10)()
num = c_int()
iResult = canBus.icsneoFindNeoDevices(c_ulong(65535), cast(iNumberOfDevices, POINT(NeoDevice)), byref(num))
ctypes是Python的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用C DLL中的函数。ctypes的官方文档在这里。1. ctypes基本数据类型映射表参数类型预先设定好,或者在调用函数时再把参数转成相应的c_***类型。ctypes的类型对应如下:ctypes typeC typePython Typec_charchar1-character stringc_wcharwch...
1 ctypes简介
从Python2.5开始引入。
ctypes是Python的外部函数库。它提供了C兼容的数据类型,并且允许调用动态链接库/共享库中的函数。它可以将这些库包装起来给Python使用。
2 ctypes入门
本入门中的代码使用doctest确保可用。不过一些代码在linux/windows/mac os x中的行为可能略有差异,这在其docte
Python中ctypes的使用整理
ctypes是
Python的一个外部
库,提供和C语言兼容的数据
类型,可以很方便地
调用C DLL
中的函数。
ctypes的官方文档在这里。
1.
ctypes基本数据
类型映射表
参数
类型预先设定好,或者在
调用函数时再把参数转成相应的c_***
类型。
ctypes的
类型对应如下:
ctypes是Python的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用C DLL中的函数。ctypes的官方文档在这里。
1. ctypes基本数据类型映射表
参数类型预先设定好,或者在调用函数时再把参数转成相应的c_***类型。ctypes的类型对应如下:
ctypes type
C type
Python Type
c_char
1-character string
c_wchar
wchar_t
1-character u.
Python 的
ctypes 要使用 C 函数,需要先将 C 编译成动态链接
库的形式,即 Windows 下的 .dll 文件,或者 Linux 下的 .so 文件。先来看一下
ctypes 怎么使用 C 标准
库。
Windows 系统下的 C 标...