Доступ к массиву структур Python в C

1

Я искал по сети без везения. У меня есть следующий код Python:

class LED(Structure):
_fields_ = [
            ('color', c_char_p),
            ('id', c_uint32)
            ]

class LEDConfiguration(Structure):
_fields_ = [
            ('daemon_user', c_char_p),
            ('leds', POINTER(LED)),
            ('num_leds', c_uint32)
            ]

Вот упрощенная примерная функция, которая использует эти структуры и возвращает LEDConfiguration.

def parseLedConfiguration(path, board):
lc = LEDConfiguration()
for config in configs:
    if( config.attributes['ID'].value.lstrip().rstrip() == board ):
        lc.daemon_user = c_char_p('some_name')
        leds = []
        #Imagine this in a loop
        ld = LED()
        ld.color = c_char_p('red')
        ld.id = int(0)
        leds.append(ld)
        #end imagined loop

        lc.num_leds = len(leds)
        lc.leds = (LED * len(leds))(*leds)

return lc

Теперь это код C, который я использую (я убрал все, что связано с настройкой python/вызовом функции parseLedConfiguration/etc, но я могу добавить его, если это будет полезно).

        /*Calling the python function "parseLedConfiguration"
          pValue is the returned "LEDConfiguration" python Structure*/

        pValue = PyObject_CallObject(pFunc, pArgs);
        Py_DECREF(pArgs);

        if (pValue != NULL)
        {
            int i, num_leds;
            PyObject *obj = PyObject_GetAttr(pValue, PyString_FromString("daemon_user"));
            daemon_user = PyString_AsString(obj);
            Py_DECREF(obj);

            obj = PyObject_GetAttr(pValue, PyString_FromString("num_leds"));
            num_leds = PyInt_AsLong(obj);
            Py_DECREF(obj);

            obj = PyObject_GetAttr(pValue, PyString_FromString("leds"));
            PyObject_Print(obj, stdout, 0);

Моя проблема заключается в том, как получить доступ к тому, что возвращается окончательному "obj". "PyObject_Print" на "obj" показывает этот вывод:

<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>

Я хочу попасть в состояние, где я могу получить доступ к этому объекту LP_LED таким же образом, как я обращаюсь к вышеуказанному объекту "LEDConfiguration".

ИЗМЕНИТЬ 1

Я думаю, что еще один важный вопрос, правильно ли мой код на Python? Так я должен хранить список или массив "Структура" внутри другой "Структуры", чтобы получить доступ к API Python C?

Благодарю!

Теги:
ctypes

1 ответ

1
Лучший ответ

Поскольку ваш EDIT 1 разъясняет основной вопрос, позвольте мне сказать, что сверху:

угадайте еще один, может быть, более важный вопрос, правильный ли код моего питона? Так я должен хранить список или массив "Структура" внутри другой "Структуры", чтобы получить доступ к API Python C?

Нет, это то, как вы должны хранить массив Structure внутри другой Structure чтобы к ней можно было получить доступ из кода, non-Python-C-API от non-Python-C-API. Если вы хотите получить доступ к API Python C, просто используйте list Python.

В общем, если вы пишете код как на Python, так и на C, только одна сторона должна наклоняться назад, чтобы работать с другой. Точка использования ctypes Structure и POINTER и т.п. В Python заключается в том, чтобы позволить им работать непосредственно на C, не ctypes C API. И наоборот, точка использования таких функций, как PyList_GetItem позволяет вам использовать обычный код Python, а не код ctypes Python.

Итак, если вы хотите сохранить list внутри Structure доступ к которой можно получить через API Python C, просто сохраните list Python - и вам действительно не нужна Structure в первую очередь; используйте обычный класс Python (возможно, с __slots__). Вы можете написать этот код, не импортируя ctypes.

И наоборот, если вы хотите хранить структуры, которые можно использовать непосредственно на C, вы можете сделать это с помощью ctypes; то, в коде C, как только вы PyObject * в Structure PyObject * вам больше не нужен API Python, потому что структура - это все C. Обычно это так, как вы делаете, когда у вас есть существующий код C, и хотите взаимодействовать с ним с Python, а не когда вы разрабатываете код C с нуля, но нет правила, в котором говорится, что вы не можете использовать его другим способом.

Между тем, если это ваша первая попытка написать коды C и Python, которые говорят друг с другом, я бы предложил вам использовать Cython. Затем, как только вам ctypes удобно, если вы хотите изучить ctypes, выполните другой проект, который использует Python с ctypes чтобы поговорить с C-кодом, который ничего не знает о Python. И затем, третий проект, который использует API C, чтобы поговорить с кодом Python, который ничего не знает о ctypes (как и большинство модулей расширения C). Как только вы знакомы со всеми тремя, вы сможете выбрать правильный вариант для большинства проектов в будущем.

Теперь, чтобы ответить на конкретную проблему:

Во-первых, когда PyList_GetItem (или большинство других функций в API C) возвращает NULL, это означает, что существует исключение, поэтому вы должны проверить исключение и зарегистрировать его. Попытка отладить возвращаемые значения NULL в API C, не глядя на исключение набора, похоже на попытку отладки кода Python, не глядя на следы.

Во всяком случае, есть несколько очевидных причин, по которым эта функция может потерпеть неудачу: возможно, вы вызываете ее с индексом вне пределов, или, может быть, вы вызываете ее на то, что не является list вообще.

На самом деле, второй кажется довольно очевидным здесь. Если распечатка obj дает вам следующее:

<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>

Затем у вас есть (указатель на) LED объект, а LED объекты не являются list.

И если вы посмотрите на свой код, у вас, похоже, нет list LED объектов в любом месте, по крайней мере, в коде, который вы нам показываете. У вас есть POINTER(LED), который может содержать C-массив-затухающий массив C LED, но это не то же самое, что и list Python. Это просто массив C, который вы используете синтаксис массива C для разыменования:

PyObject *led = ledarray[i];
  • 0
    Спасибо, Абарнерт. Я сделал правку, которая может быть более актуальным первым вопросом. Знаете ли вы, как я могу получить доступ к этому POINTER (LED) (AKA LP_LED) из C? Похоже, чтобы получить доступ к нему как массив, мне нужно в конечном итоге с LP_LP_LED или что-то может быть?
  • 0
    LP_LED в основном является typedef для LED * . Другими словами, это фактически PyObject ** . Как и в случае с любым указателем C, если он действительно указывает на массив, вы можете просто использовать его как массив; если бы это был указатель на указатель на массив, это было бы не намного сложнее; просто (*ledarray)[i] . Какой у вас опыт работы с указателями и массивами Си?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню