Обычно модуль ctypes
выполняет строгую проверку типов. Это означает, что если есть POINTER(c_int)
в списке типов аргументов функции или в качестве типа поля члена в определении структуры, то принимаются только экземпляры одного и того же типа.
Есть некоторые исключения из этого правила, когда ctypes
принимает другие объекты. Например, можно передать совместимые экземпляры массивов вместо типов указателей. Итак, для POINTER(c_int)
, ctypes
принимает массив c_int
:
>>> from ctypes import * >>> 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)
) в атрибуте .argtypes
, то объект указанного типа (в данном случае ctypes.c_int
) может быть передан функции. В этом случае модуль ctypes
применит необходимое преобразование ctypes.byref()
автоматически.
Чтобы установить для поля типа POINTER
значение NULL
, необходимо назначить None
:
>>> bar.values = None
Иногда встречаются экземпляры несовместимых типов. В языке C можно преобразовать один тип в другой. Модуль ctypes
предоставляет функцию ctypes.cast()
, которую можно использовать таким же образом. Определенная выше структура Bar
принимает указатели POINTER(c_int)
или массивы c_int
для своего поля 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
В этих случаях удобна функция ctypes.cast()
.
Функцию ctypes.cast()
можно использовать для преобразования экземпляра ctypes
в указатель на другой тип данных ctypes
. Функцию ctypes.cast()
принимает два параметра: объект ctypes
, который является или может быть преобразован в какой-либо указатель, и тип указателя ctypes
. Он возвращает экземпляр второго аргумента, который ссылается на тот же блок памяти, что и первый аргумент:
>>> a = (c_byte * 4)() >>> cast(a, POINTER(c_int)) # <ctypes.LP_c_long object at ...>
Итак, ctypes.cast()
можно использовать для присвоения полю значений структуры Bar
:
>>> bar = Bar() >>> bar.values = cast((c_byte * 4)(), POINTER(c_int)) >>> print(bar.values[0]) # 0