隐式转换
首先我们在c语言里面,两边都可以向中间转换
非数字类型 | 整型 | 浮点型 |
char | float | |
unsigned char | int | double |
* | long |
那么在python中。
如果你的参数中有一个指针类型的 POINTER(),或者是有一个结构体成员中有这一类型。只有实例对象和类型完全一样才会接受。(显示声明传入类型在前面有提到,通过属性argtypes进行限定)
特例:如果你传入一个兼容的array对象而不是pointer对象。那么对于POINTER(c_int),ctypes会接受一个c_int的数组。同c语言的指针和数组关系。
>>> class Bar(Structure):
... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
... print(bar.values[i])
...
1
2
3
>>>
如果一个方法显示的声明了是一个指针类型,比如()POINTER(c_int),那么如果是一个被指向类型的参数,
这种情况下。ctypes将会通过byref自动做出调整。
如果需要的是 POINTER(c_int)传入int,就会自动的通过 byref(c_int)进行生成一个指针类型。
如果创建一个空指针,设置一个空指针
bar.values = None
强制转换 cast
有时候类型不匹配,在c中,可以通过强制转换。
ctypes中提供了 cast 方法来实现。
接着上面的Bar类,我们可以知道Bar结构体定义了接受指针或者是数组的values字段,而不是其他类型。
>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>
在上面的案例,传入了一个长度为4的c_byte数组,并且初始值为0.但是接受的是 一个c_int。
对于这种情况下,cast方法是非常方便的。
cast方法可以用来将C风格的普通类型转化成为指向其他类型的C类型。
cast接受两个参数z,c风格的类型是一个指针或者是可以被转换为一个指针。返回第二个参数类型的对象。
cast也就是某一种指针转换成为另一种指针,然后指向的内存一样,也就是地址不变。
>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>
这里,我们可以看到这是一个大端序
我们看一下linux的
也就是默认是大端序
通过C测试出来 也是大端。
大端方便我们阅读,偏移的时候也可以从低位往高位偏移。如果溢出,那么就使用未溢出也就是合法内存内的数据。
这种即使在溢出的情况下,低位的仍然保持数据的正确性。而且,网络字节序也是大端。
大端大端,即大在端点,小在起点。
>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>
同样的cast的结果可以用来给values赋值。