我可以通过两种方式定义包含字节数组的结构,作为 c_char 数组或 c_ubyte 数组:
import ctypes
class Char(ctypes.Structure):
_fields_ = [('value',ctypes.c_char * 12)]
class Byte(ctypes.Structure):
_fields_ = [('value',ctypes.c_ubyte * 12)]
我可以非常直接地为 Char() 实例赋值:
>>> ci = Char()
>>> ci.value = b'Hello world'
>>> print(ci.value)
b'Hello world'
但是如果我尝试对 Byte() 实例进行类似的赋值,我会得到一个 TypeError:
>>> bi = Byte()
>>> bi.value = b'Hello world'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected c_ubyte_Array_12 instance, got bytes
C 并没有真正的字节类型,所以我可以使用 c_char,但我觉得使用 ctypes c_ubyte 更清楚地揭示了我的意图,这就是我尝试的原因。
是否有充分的理由不允许将 Python 字节分配给 ctypes.c_ubyte 数组?这对我来说似乎很奇怪,所以我担心我对 c_ubyte 有一些不理解的地方。
c_char
在结构中具有特殊的默认处理,将其视为以 null 结尾的字符串。 c_ubyte
(和c_byte
,签名版本)不要这样做。 您仍然可以使用字节字符串分配给它们,但需要使用切片并分配与切片大小相同的字节字符串:
import ctypes
class Char(ctypes.Structure):
_fields_ = [('value',ctypes.c_char * 12)]
def __repr__(self):
return f'Char({self.value})'
class Byte(ctypes.Structure):
_fields_ = [('value', ctypes.c_ubyte * 12)]
def __repr__(self):
return f'Byte({bytes(self.value)})'
c = Char()
print(c.value) # converted to byte string. doesn't show nulls
c.value = b'hello'
print(c) # b'hello'
c.value = b'123456789abc'
print(c) # b'123456789abc'
try:
c.value = b'123456789abcd' # error: too long
except ValueError as e:
print(e)
b = Byte()
print(b.value) # still an array
b.value[:5] = b'hello' # assign 5-byte string to 5-byte slice.
print(b) # shows nulls
b.value[:] = b'123456789abc' # array size is 12, string exactly fits, no nulls
print(b)
try:
b.value[:] = b'123456789ab' # array size is 12, byte string is 11, error: too short
except ValueError as e:
print(e)
输出:
b''
Char(b'hello')
Char(b'123456789abc')
bytes too long (13, maximum length 12)
<__main__.c_ubyte_Array_12 object at 0x0000022D5EC2F850>
Byte(b'hello\x00\x00\x00\x00\x00\x00\x00')
Byte(b'123456789abc')
Can only assign sequence of same size