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
  1. Objdll = ctypes.cdll.LoadLibrary( "dllpath" )
  2. 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
  1. >>> p = create_string_buffer( "Hello" , 10 ) # create a 10 byte buffer
  2. >>> print sizeof(p), repr(p.raw)
  3. 10 'Hello/x00/x00/x00/x00/x00'

不带参数的调用指针类型创建一个NULL指针, NULL指针有一个False布尔值

[python] view plain
  1. >>> null_ptr = POINTER(c_int)()
  2. >>> print bool(null_ptr)
  3. 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
  1. from ctypes import *
  2. import types
  3. class Test(Structure):
  4. _fields_ = [( 'x' , c_int),
  5. ( 'y' , c_char)]
  6. test1 = Test( 1 , 2 )

另外,如结构体用于链表操作,即包含指向结构体指针时,若直接定义:

[python] view plain
  1. from ctypes import *
  2. import types
  3. class Test(Structure):
  4. _fields_ = [( 'x' , c_int),
  5. ( 'y' , c_char),
  6. ( 'next' , Test)]

则python会报错type未定义,:

[python] view plain
  1. from ctypes import *
  2. import types
  3. class Test(Structure):
  4. pass
  5. Test._fields_ = [( 'x' , c_int),
  6. ( 'y' , c_char),
  7. ( 'next' , POINTER(Test))]

6. 数组定义

数组包含一个固定数目的相同类型的实例,常用创建数组类型是对一个数据类型与一个正数相乘,例如:

[python] view plain
  1. 初始化和使用数组:
  2. <span style= "color:#0000ff;" >>>> from ctypes import *
  3. >>> TenIntegers = c_int * 10
  4. >>> ii = TenIntegers( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 )
  5. >>> print ii
  6. <c_long_Array_10 object at 0x ...>
  7. >>> for i in ii: print i,
  8. </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开始引入。
ctypesPython的外部函数。它提供了C兼容的数据型,并且允许调用动态链接/共享的函数。它可以将这些包装起来给Python使用。
2  ctypes入门
本入门的代码使用doctest确保可用。不过一些代码在linux/windows/mac os x的行为可能略有差异,这在其docte
				
Pythonctypes的使用整理 ctypesPython的一个外部,提供和C语言兼容的数据型,可以很方便地调用C DLL的函数。ctypes的官方文档在这里。 1. ctypes基本数据型映射表 参数型预先设定好,或者在调用函数时再把参数转成相应的c_***型。ctypes型对应如下:
ctypesPython的一个外部,提供和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.
Pythonctypes 要使用 C 函数,需要先将 C 编译成动态链接的形式,即 Windows 下的 .dll 文件,或者 Linux 下的 .so 文件。先来看一下 ctypes 怎么使用 C 标准。 Windows 系统下的 C 标...