Сообщить об ошибке.

Примеры преобразований модуля ctypes в Python

Обычно модуль 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