在C中访问python结构数组

时间:2012-12-12 18:11:25

标签: python c ctypes

我一直在网上搜索,没有运气。我有以下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”函数/等的所有内容,但如果有帮助我可以添加它。)

        /*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>

我想进入一个可以访问LP_LED对象的状态,就像我访问上面的“LEDConfiguration”对象一样。

编辑1

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

谢谢!

1 个答案:

答案 0 :(得分:1)

由于您的编辑1澄清了基本问题,让我把它放在最上面:

  猜猜另一个可能更重要的问题,我的python代码是否正确?这是我应该如何将“结构”的列表或数组存储在另一个“结构”中,以便可以从Python C API访问它?

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

通常,如果您在Python和C中编写代码,则只有一方必须向后弯曲以与另一方一起工作。在Python中使用ctypes StructurePOINTER等等的重点是允许他们在C中直接工作,而无需经历C API。相反,使用像PyList_GetItem这样的函数的关键是允许你使用普通的Python代码,而不是ctypes Python代码。

所以,如果你想在list内存储一个Structure来通过Python C API访问,只需存储一个Python list - 你真的不需要Structure首先是__slots__;使用普通的Python类(可能使用ctypes)。您可以编写此代码而无需导入ctypes

相反,如果要存储可以直接在C中使用的结构,可以使用Structure执行此操作;然后,在C代码中,一旦你进入PyObject * Cython胆量,你不再需要Python API了,因为结构都是C.这通常是你去的方式当你有现有的C代码,并希望从Python接口时,而不是从头开始设计C代码,但是没有规则说你不能以其他方式使用它。

同时,如果这是您第一次尝试编写彼此交谈的C和Python代码,我建议您使用ctypes。然后,如果您对此感到满意,如果您想学习ctypes,请使用Python与ctypes进行不同的项目,以便与对Python完全一无所知的C代码进行对话。然后,第三个使用C API与Python代码交谈的项目,该代码对PyList_GetItem一无所知(与大多数C扩展模块一样)。一旦熟悉了这三个项目,您将来可以为大多数项目选择合适的项目。

现在,回答具体问题:

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

无论如何,这个函数可能会失败有一些明显的原因:也许你用一个越界索引来调用它,或者你可能在一个不是obj的东西上调用它一点都不。

事实上,第二个看起来非常明显。如果打印<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>给你这个:

LED

然后你有一个(指向一个)LED对象的指针,list个对象不是list

如果你查看你的代码,你似乎没有LEDPOINTER(LED)个对象,至少在你给我们看的代码中没有。你有一个LED,它可以容纳一个C-array衰变的list的C数组,但这与它们的Python PyObject *led = ledarray[i]; 不同。它只是一个C数组,您可以使用C数组语法取消引用:

{{1}}