核心概念
- 类型一览
ctypes是python定义的为实现类型转换的中间层,是纯python数据类型与c类型通信的桥梁.
除了None,integer,string,bytes,(隐式转换), 其他都需要转换成ctypes类型作为参数.
None -->NULL
string bytes -- > char* wchar_t*
integer -- > int
#c_double 必须显示转换
printf(b'Hello %s %f\n', b'Wisdom', c_double(1.23))
标准类型里唯一要注意的是c_char_p,很像C里的字符串类型, 它只能转换integer或者bytes作为输入.
普通的’char *'类型用POINTER(c_char)
class ctypes.c_char_p
Represents the C char * datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, POINTER(c_char) must be used. The constructor accepts an integer address, or a bytes object.
- 严格区分类型
不像c指针那么万能,python里一切皆对象.数组,指针都是要按不同的类型来分开的。
1 int a = 100;
----> ct_a = c_int(100)
2 int array[100] = {0,1,2,...}
---->ct_array = (c_int* 100)(0,1,2,...)
for i in ct_array: print(i)
3 int *ptr = &a;
----> ct_ptr = POINTER(c_int)(ct_a)
ct_ptr.contents
c_int(10)
4 *ptr = 200 ;
// ptr[0] = 200
----> ct_ptr[0] = 200 or ct_ptr.contents.value = 300
5 int *ptr_arr = array;
----> ctype做不到! 对python 来讲,数组和指针是不同的类型
- Access dll function and values
function见下面例2.
value:
>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
>>> print(opt_flag)
c_long(0)
- resttype argstype
load c的lib后,必须告诉Python,一个ctype函数的形参类型和返回的值的类型, 函数才能正确地在python里调用.
libusb_alloc_transfer = libusb.libusb_alloc_transfer
libusb_alloc_transfer.argtypes = [c_int]
libusb_alloc_transfer.restype = libusb_transfer_p
- convert python type to ctype
1.构造ctype对象时输入;
2.通过value输入输入;
ct_int = ctypes.c_int(100)
ct_int.value
100
ct_int.value = 200
ct_int
c_int(200)
如果是ctype指针,也是要通过赋值:
但是python的bytes是immutable的,也就是bytes内容变化,是指向了另外的内存,而不是内存内容本身发生了变化,这和c的一些要求是不符合的:
ct_str = ctypes.c_wchar_p('Hi!')
ct_str.value
'Hi!'
ct_str
c_wchar_p(140093580736096)
ct_str = ctypes.c_wchar_p('Hi again')
ct_str.value
'Hi again'
ct_str
c_wchar_p(140093530479112)
用下面的 create_string_buffer解决问题
- create_string_buffer
创建可修改的ctype内存空间
>>buf = create_string_buffer(b'12345')
>>buf.value
>>b'12345'
- byref and pointer and POINTER
byref
:
拿到ctype instance的指针对象,,offset是偏移的地址. 但是只能用作ctype函数的参数,比pointer(obj)更快.
pointer
:
pointer则是构造ctype对象的ctype pointer实例对象,普通对象变成指针对象
ctypes.pointer(obj)
Pointer instances are created by calling the pointer() function on a ctypes type.
This function creates a new pointer instance, pointing to obj. The returned object is of the
type POINTER(type(obj)).
用contents取出内容,类似于*a
:
- POINTER
POINTER仅仅是ctype层面的指针类型转换,比如1个ctypes类型转成其指针的类型,类型变成指针类型
ctypes.POINTER(type)
This factory function creates and returns a new ctypes pointer type. Pointer types are
cached and reused internally, so calling this function repeatedly is cheap. type must be a
ctypes type.
例子:
libc.printf(b'%x',byref(c_int(123)))
>>bf60f9188
type(byref(c_int(123)))
ct_int = ct_int(123)
>> <class 'CArgObject'>
ip = pointer(ct_int)
type(ip)
>> <class '__main__.LP_c_int'>
ip.contents
>>c_int(0)
type_int_p = POINTER(c_int)
type(type_int_p)
>> <class '_ctypes.PyCPointerType'>
ip_1 = type_int_p(c_int(123))
ip_1.contents
>>c_int(123)
type(ip_1)
<class '__main__.LP_c_int'>
>>False
- Structure
参考下面例子里定义.
1.注意一点,字节序是native bytes order.
2.前向声明结构体的方式:
>>> from ctypes import *
#先声明1个空的
>>> class cell(Structure):
... pass
...
#直接赋值_fields_的属性
>>> cell._fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
>>>
- Array
不同类型再乘以1个数即得到数组.
ct_int_array = c_int * 10
type(ct_int_array)
<class '_ctypes.PyCArrayType'>
- memmove memset
ctypes.memmove(dst, src, count)
Same as the standard C memmove library function: copies count bytes from src to dst. dst and src must be integers or ctypes instances that can be converted to pointers.
ctypes.memset(dst, c, count)
Same as the standard C memset library function: fills the memory block at address dst with count bytes of value c. dst must be an integer specifying an address, or a ctypes instance.
- cast:
类似c