python и ctypes обращаются к классам c ++ с вложенными структурами - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть общая библиотека и два заголовочных файла. Я смог использовать библиотеку, создав привязки, используя swig. Однако версия swig довольно медленная, и мне не удалось включить поддержку массивов numpy. Сейчас я пытаюсь вызвать функции библиотеки из Python, используя ctypes.

Первый заголовок содержит блок extern "C", который экспортирует 3 функции через макросы (которые мне недоступны). Упрощенная версия заголовка выглядит так:

...

class Foo;
typedef Foo* FOO_HANDLE;

#if !defined(__cplusplus)
#   error "C++ Compiler only"
#endif

extern "C"
{
    APIPROTOTYPE_EXT( MakeAlgo, FOO_HANDLE, (void) );

    APIPROTOTYPE_EXT( DestroyAlgo, void, ( FOO_HANDLE ) );

    APIPROTOTYPE_EXT( AlgoProcess, void, ( FOO_HANDLE, StructOne *, StructTwo *) );
}

Обычно первая функция MakeAlgo возвращает указатель на экземпляр класса Foo, вторая функция DestroyAlgo уничтожает экземпляр, а третья функция AlgoProcess принимает в качестве входных данных две структуры и изменяет некоторые их значения на месте.

Второй заголовок содержит определения StructOne и StructTwo и некоторые константы. StructTwo содержит несколько вложенных структур.

В Python я переписал все структуры, содержащиеся во втором заголовке, используя ctypes.Structure. Я не публикую здесь весь код, но вот пример того, как я определил вложенную структуру:

class StructTwo(Structure):
    _fields_ = [("foo", StructFoo),
                ("dummy8", c_short)]

class StructFoo(Structure):
    _fields_ = [("bar", c_uint),
                ("reserv1", c_uint),
                ("reserv2", c_uint)]

Тогда мой код Python выглядит следующим образом (при условии, что структуры находятся в файле structures.py):

from ctypes import *
from structures import StructOne, StructTwo

libfoo = ct.cdll.LoadLibrary(path/to/so/library)

makeAlgo = libfoo.MakeAlgo
makeAlgo.restype = c_void_p
makeAlgo.argtypes = []

destroyAlgo = libfoo.DestroyAlgo
destroyAlgo.restype = None
destroyAlgo.argtypes = [c_void_p]

submit = libfoo.AlgoProcess
submit.restype = None
submit.argtypes = [c_void_p, POINTER(StructOne), POINTER(StructTwo)]

handle = makeAlgo()

one = bar.StructOne()
two = bar.StructTwo()

submit(handle, byref(one), byref(two))
print(two.foo.bar)  # unsigned int, should output 1, got 196611000 instead

destroyAlgo(handle)

После создания указателя на класс Foo и отправки входных данных я проверяю некоторые значения в одной из структур, и они не соответствуют ожидаемому результату. Например, я знаю, что одно из полей установлено библиотекой только на 0 или 1, но я получаю странные результаты, например, 196611000.

Кто-нибудь знает, что не так (может, у кого-то была похожая проблема)? Может быть, так, как я определил структуры? Или, может быть, это указатель на класс C ++, который обрабатывается неправильно?

EDIT

Мне удалось решить начальную проблему. Похоже, что способ, которым я определяю структуры, был неправильным. Вместо приведенного выше кода, вложенные структуры должны передаваться по ссылке:

class StructTwo(Structure):
    _fields_ = [("foo", POINTER(StructFoo)),
                ("dummy8", c_short)]

class StructFoo(Structure):
    _fields_ = [("bar", c_uint),
                ("reserv1", c_uint),
                ("reserv2", c_uint)]

# Then to initialize the nested structure
foo = StructFoo()
two = StructTwo(pointer(foo))  # has to be pointer() not byref()

Однако теперь, чтобы получить доступ к полям StructFoo, мне нужно сделать:

print(two.foo.contents.bar)

В реальном коде у меня может быть до 4 вложенных уровней. Есть ли более элегантный способ доступа к их полям, чем:

two.foo.contents.baz.contents.qux.contents.field_value

1 Ответ

0 голосов
/ 26 апреля 2018

Мое редактирование было неверным.

Проблема заключалась в том, что некоторые структуры были структурами битового поля, указание ширины каждого поля решало ее:

class StructTwo(Structure):
    _fields_ = [("foo", StructFoo),
                ("dummy8", c_short)]

class StructFoo(Structure):
    _fields_ = [("bar", c_uint, 1),
                ("reserv1", c_uint, 8),
                ("reserv2", c_uint, 16)]

Битструктуры в типах .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...