用C语言访问python结构数组

2024-06-30 07:54:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在网上搜索,但没找到。我有以下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的简化示例函数。在

^{pr2}$

现在这是我使用的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”的内容。“obj”上的“PyObject_Print”显示以下输出:

<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>

我想进入一种状态,在这种状态下,我可以用访问上述“LEDConfiguration”对象的方式访问LP_-LED对象。在

编辑1

我想另一个可能更重要的问题是,我的python代码正确吗?这就是我应该如何将“Structure”的列表或数组存储在另一个“Structure”中,以便可以从pythoncapi访问它吗?在

谢谢!在


Tags: 代码pyobjledstructurenumdaemonpyobject
1条回答
网友
1楼 · 发布于 2024-06-30 07:54:31

既然你的编辑1澄清了潜在的问题,让我把它放在首位:

guess another maybe more important question, is my python code correct? Is that how I should be storing a list or array of "Structure" inside another "Structure" so it can be accessed from the Python C API?

不,这就是您应该如何将Structure数组存储在另一个Structure中,以便可以从non-Python-C-APIC代码中访问它。如果希望从pythoncapi访问它,只需使用Pythonlist。在

一般来说,如果你同时用Python和C编写代码,那么只有一方必须向后弯曲才能与另一方协同工作。在Python中使用ctypesStructures和POINTERs等的目的是允许它们直接在C中工作,而不必经过C API。相反,使用PyList_GetItem这样的函数的目的是允许您使用普通的Python代码,而不是ctypesPython代码。在

因此,如果您想将list存储在要通过pythoncapi访问的Structure中,只需存储一个Python list-而且您实际上一开始就不需要Structure;使用普通的Python类(可能与__slots__一起使用)。您完全可以不导入ctypes来编写此代码。在

相反,如果您想存储可以直接在C中使用的结构,可以使用ctypes;然后,在C代码中,一旦您进入PyObject *的{}内部,就不再需要PythonAPI了,因为结构都是C的。当您有了现有的C代码并希望与之交互时,通常就是这样而不是从头开始设计C代码,但是没有规则表明不能用其他方式使用它。在

同时,如果这是您第一次尝试编写相互通信的C和Python代码,我建议您使用Cython。然后,一旦您熟悉了这一点,如果您想学习ctypes,那么可以做一个不同的项目,使用Python和{}来与对Python一无所知的C代码进行对话。然后,第三个项目使用C API与Python代码进行对话,而Python代码对ctypes(与大多数C扩展模块一样)一无所知。一旦你熟悉了这三种方法,你就可以为将来的大多数项目选择合适的一种。在

现在,回答具体问题:

首先,当PyList_GetItem(或C API中的大多数其他函数)返回NULL时,这意味着存在异常,因此您应该检查异常并记录它。尝试调试C API中的空返回值而不查看设置异常,就像尝试调试Python代码而不查看回溯一样。在

无论如何,有几个明显的原因导致这个函数失败:也许你用一个越界索引调用它,或者你调用它的对象根本不是list。在

事实上,第二个问题在这里似乎很明显。如果打印出obj会给您提供以下信息:

<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>

然后你得到了一个指向LED对象的(指针),而LED对象不是{}s

如果你看看你的代码,你似乎没有list对象,至少在你展示给我们的代码中没有。你确实有一个POINTER(LED),它可以保存一个由LED组成的C数组,但这与其中的Pythonlist不是一回事。它只是一个C数组,您可以使用C数组语法来取消引用:

PyObject *led = ledarray[i];

相关问题 更多 >