c_long和c_int是一种类型。
cdll加载使用标准cdecl调用约定导出函数的库
windll使用stdcall调用约定调用函数
oledll也使用stdcall调用约定
在linux下通过两种方法加载动态链接库:
1.cdll.LoadLibrary("libc.so.6")
2.CDLL("libc.so.6")
(结果相同)
如何告诉Python一个外来函数的形参类型和返回的值的类型呢?
答:给函数的两个属性restype和argtypes赋值。
restype-------返回类型
argtypes------参数类型
例如某函数的返回类型是float,对应到Python里就是c_float。
dll.addf.restype = c_float
如果函数的返回值是void那么可以赋值为None。另外,可以使用python 内置类型“描述”库函数的返回类型,但是,不可以用python内置类型来描述库函数的参数类型。
由于函数的参数不是固定的数量,所以需要使用列表或者是元祖来说明:
dll.addf.argtypes = (c_float,c_float)
or
dll.addf.argtypes = [c_float,c_float]
创建一个ctypes的类型(c_int、c_float、c_char...)并给他赋值
i = c_int(45)
i.value
or
i.value = 56
i.value
结构体跳过
指针
创建一个ctypes的指针:
1.byref(x[,offset]):返回x的地址,x必须为ctypes类型的一个实例。相当于c的&x。offset表示偏移量。(通过引用传递参数)
2.pointer(x):创建并返回一个指向x的指针实例,x是一个实例对象。(构造了一个真正的指针对象,因此这种方法做了很多工作,会更慢相对byref)
3.POINTER(type):返回一个类型,这个类型是指向type类型的指针类型,type是ctypes的一个类型。
eg:
>>> a = c_int(66) # 创建一个 c_int 实例
>>> b = pointer(a) # 创建指针
>>> c = POINTER(c_int)(a) # 创建指针
>>> b
<__main__.LP_c_long object at 0x00E12AD0>
>>> c
<__main__.LP_c_long object at 0x00E12B20>
>>> b.contents # 输出 a 的值
c_long(66)
>>> c.contents # 输出 a 的值
c_long(66)
令POINTER(c_int)为pointer
pointer创建的指针貌似不能修改ctypes类型
print_point函数:
>>> dll.print_point.argtypes = (POINTER(Point),) # 指明函数的参数类型
>>> dll.print_point.restype = None # 指明函数的返回类型
>>>
>>> p = Point(32.4, -92.1) # 实例化一个 Point
>>> dll.print_point(byref(p)) # 调用函数
position x 32.400002 y -92.099998>>>
当然你非要用慢一点的 pointer 也行:
>>> dll.print_point(pointer(p)) # 调用函数
position x 32.400002 y -92.099998
关于byref()-即用引用传递参数:
一般适用于需要C函数修改传入的参数,或者参数过大不适合传值,这时就要用到按引用传递。
eg:
from ctypes import *
'''
windows下
libc = cdll.LoadLibrary('msvcrt.dll')
'''
#linux下
libc = cdll.LoadLibrary('libc.so.6')
i = c_int()
f = c_float()
s = create_string_buffer(b'\000' * 32)
print 'i.val =', i.value
print 'f.val =', f.value
print 'repr(s.value) =', repr(s.value)
libc.sscanf(b'1 3.14 Hello', b'%d %f %s', byref(i), byref(f), s)
#3表示正确返回,0 表示不正确返回
print 'after, i.val =', i.value
print 'after, f.val =', f.value
print 'after, repr(s.value) =', repr(s.value)
输出:
i.val = 0
f.val = 0.0
repr(s.value) = ''
after, i.val = 1
after, f.val = 3.1400001049
after, repr(s.value) = 'Hello'
数组
数组是序列,包含固定数量的相同类型的实例。
推荐的创建数组类型的方法是将数据类型乘以正整数:
TenPointsArrayType = POINT * 10
官方文档给出的例子是eg:
>>> from ctypes import *
>>> class POINT (Structure ):
... _fields_ = (“x” , c_int ), (“y” , c_int )
...
>>> class MyStruct (Structure ):
.. 。 _fields_ = [( “ 一” , c_int的),
... (“b” , c_float ),
... (“point_array” , POINT * 4 )]
>>>
>>> print (len (MyStruct ()。point_array ))
4
更好的例子eg:
>>> class POINT(Structure):
#括号里第一个参数是形参的名字
... _fields_=("x",c_int),("y",c_int)
...
>>> class MyStruct(Structure):
... _fields_=[("a",c_int),("b",c_float),("point_array",POINT*4)]
...
>>> print(len(MyStruct().point_array))
4
>>> TenIntArrayType = c_int * 10
#如果不赋值,默认是0
>>> ta = TenIntArrayType(1,2,3,4,5,6,7,8,9,10)
>>> for item in ta:
... print(item)
...
1
2
3
4
5
6
7
8
9
10
>>> ms = MyStruct(4,5,((1,1),(2,2),(3,3),(4,4)))
>>> for item in ms.point_array:
... print('(item.x,item.y) = (%d,%d)' % (item.x,item.y))
...
(item.x,item.y) = (1,1)
(item.x,item.y) = (2,2)
(item.x,item.y) = (3,3)
(item.x,item.y) = (4,4)
>>>
pointer()函数指针:
>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>> pi.contents
c_long(42)
注意ctypes都没有原始对象返回,也就是说每次调用pi属性时重新创建一个新的对象,那么就是:
>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
在幕后,pointer()不仅创建指针实例,它必须首先创建指针类型。这是通过POINTER()接受任何ctypes类型的函数完成的,并返回一个新类型。
调用没有参数的指针类型将创建一个NULL指针。 NULL指针有一个False布尔值:
>>> null_ptr = POINTER (c_int )()
>>> print (bool (null_ptr ))
False
>>>
cdll加载使用标准cdecl调用约定导出函数的库
windll使用stdcall调用约定调用函数
oledll也使用stdcall调用约定
在linux下通过两种方法加载动态链接库:
1.cdll.LoadLibrary("libc.so.6")
2.CDLL("libc.so.6")
(结果相同)
如何告诉Python一个外来函数的形参类型和返回的值的类型呢?
答:给函数的两个属性restype和argtypes赋值。
restype-------返回类型
argtypes------参数类型
例如某函数的返回类型是float,对应到Python里就是c_float。
dll.addf.restype = c_float
如果函数的返回值是void那么可以赋值为None。另外,可以使用python 内置类型“描述”库函数的返回类型,但是,不可以用python内置类型来描述库函数的参数类型。
由于函数的参数不是固定的数量,所以需要使用列表或者是元祖来说明:
dll.addf.argtypes = (c_float,c_float)
or
dll.addf.argtypes = [c_float,c_float]
创建一个ctypes的类型(c_int、c_float、c_char...)并给他赋值
i = c_int(45)
i.value
or
i.value = 56
i.value
结构体跳过
指针
创建一个ctypes的指针:
1.byref(x[,offset]):返回x的地址,x必须为ctypes类型的一个实例。相当于c的&x。offset表示偏移量。(通过引用传递参数)
2.pointer(x):创建并返回一个指向x的指针实例,x是一个实例对象。(构造了一个真正的指针对象,因此这种方法做了很多工作,会更慢相对byref)
3.POINTER(type):返回一个类型,这个类型是指向type类型的指针类型,type是ctypes的一个类型。
eg:
>>> a = c_int(66) # 创建一个 c_int 实例
>>> b = pointer(a) # 创建指针
>>> c = POINTER(c_int)(a) # 创建指针
>>> b
<__main__.LP_c_long object at 0x00E12AD0>
>>> c
<__main__.LP_c_long object at 0x00E12B20>
>>> b.contents # 输出 a 的值
c_long(66)
>>> c.contents # 输出 a 的值
c_long(66)
令POINTER(c_int)为pointer
pointer创建的指针貌似不能修改ctypes类型
print_point函数:
>>> dll.print_point.argtypes = (POINTER(Point),) # 指明函数的参数类型
>>> dll.print_point.restype = None # 指明函数的返回类型
>>>
>>> p = Point(32.4, -92.1) # 实例化一个 Point
>>> dll.print_point(byref(p)) # 调用函数
position x 32.400002 y -92.099998>>>
当然你非要用慢一点的 pointer 也行:
>>> dll.print_point(pointer(p)) # 调用函数
position x 32.400002 y -92.099998
关于byref()-即用引用传递参数:
一般适用于需要C函数修改传入的参数,或者参数过大不适合传值,这时就要用到按引用传递。
eg:
from ctypes import *
'''
windows下
libc = cdll.LoadLibrary('msvcrt.dll')
'''
#linux下
libc = cdll.LoadLibrary('libc.so.6')
i = c_int()
f = c_float()
s = create_string_buffer(b'\000' * 32)
print 'i.val =', i.value
print 'f.val =', f.value
print 'repr(s.value) =', repr(s.value)
libc.sscanf(b'1 3.14 Hello', b'%d %f %s', byref(i), byref(f), s)
#3表示正确返回,0 表示不正确返回
print 'after, i.val =', i.value
print 'after, f.val =', f.value
print 'after, repr(s.value) =', repr(s.value)
输出:
i.val = 0
f.val = 0.0
repr(s.value) = ''
after, i.val = 1
after, f.val = 3.1400001049
after, repr(s.value) = 'Hello'
数组
数组是序列,包含固定数量的相同类型的实例。
推荐的创建数组类型的方法是将数据类型乘以正整数:
TenPointsArrayType = POINT * 10
官方文档给出的例子是eg:
>>> from ctypes import *
>>> class POINT (Structure ):
... _fields_ = (“x” , c_int ), (“y” , c_int )
...
>>> class MyStruct (Structure ):
.. 。 _fields_ = [( “ 一” , c_int的),
... (“b” , c_float ),
... (“point_array” , POINT * 4 )]
>>>
>>> print (len (MyStruct ()。point_array ))
4
更好的例子eg:
>>> class POINT(Structure):
#括号里第一个参数是形参的名字
... _fields_=("x",c_int),("y",c_int)
...
>>> class MyStruct(Structure):
... _fields_=[("a",c_int),("b",c_float),("point_array",POINT*4)]
...
>>> print(len(MyStruct().point_array))
4
>>> TenIntArrayType = c_int * 10
#如果不赋值,默认是0
>>> ta = TenIntArrayType(1,2,3,4,5,6,7,8,9,10)
>>> for item in ta:
... print(item)
...
1
2
3
4
5
6
7
8
9
10
>>> ms = MyStruct(4,5,((1,1),(2,2),(3,3),(4,4)))
>>> for item in ms.point_array:
... print('(item.x,item.y) = (%d,%d)' % (item.x,item.y))
...
(item.x,item.y) = (1,1)
(item.x,item.y) = (2,2)
(item.x,item.y) = (3,3)
(item.x,item.y) = (4,4)
>>>
pointer()函数指针:
>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>> pi.contents
c_long(42)
注意ctypes都没有原始对象返回,也就是说每次调用pi属性时重新创建一个新的对象,那么就是:
>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
在幕后,pointer()不仅创建指针实例,它必须首先创建指针类型。这是通过POINTER()接受任何ctypes类型的函数完成的,并返回一个新类型。
调用没有参数的指针类型将创建一个NULL指针。 NULL指针有一个False布尔值:
>>> null_ptr = POINTER (c_int )()
>>> print (bool (null_ptr ))
False
>>>
参考:点击打开链接