7

有一种方法可以用字典初始化结构:

fooData= {'y': 1, 'x': 2}
fooStruct = ffi.new("foo_t*", fooData)
fooBuffer = ffi.buffer(fooStruct)

是否有一些现成的功能可以进行转换?

fooStruct = ffi.new("foo_t*")
(ffi.buffer(fooStruct))[:] = fooBuffer
fooData= convert_to_python( fooStruct[0] )    

我必须自己使用 ffi.typeof("foo_t").fields 吗?

到目前为止,我想出了这段代码:

def __convert_struct_field( s, fields ):
    for field,fieldtype in fields:
        if fieldtype.type.kind == 'primitive':
            yield (field,getattr( s, field ))
        else:
            yield (field, convert_to_python( getattr( s, field ) ))

def convert_to_python(s):
    type=ffi.typeof(s)
    if type.kind == 'struct':
        return dict(__convert_struct_field( s, type.fields ) )
    elif type.kind == 'array':
        if type.item.kind == 'primitive':
            return [ s[i] for i in range(type.length) ]
        else:
            return [ convert_to_python(s[i]) for i in range(type.length) ]
    elif type.kind == 'primitive':
        return int(s)

有更快的方法吗?

4

3 回答 3

4

Arpegius 的解决方案对我来说效果很好,而且非常优雅。我根据 Selso 的使用检查的建议实施了一个解决方案。dir() 可以代替检查。

from inspect import getmembers
from cffi import FFI
ffi = FFI()
from pprint import pprint

def cdata_dict(cd):
    if isinstance(cd, ffi.CData):
        try:
            return ffi.string(cd)
        except TypeError:
            try:
                return [cdata_dict(x) for x in cd]
            except TypeError:
                return {k: cdata_dict(v) for k, v in getmembers(cd)}
    else:
        return cd

foo = ffi.new("""
struct Foo {
    char name[6];
    struct {
        int a, b[3];
    } item;
} *""",{
    'name': b"Foo",
    'item': {'a': 3, 'b': [1, 2, 3]}
})
pprint(cdata_dict(foo))

输出:

{'item': {'a': 3, 'b': [1, 2, 3]}, 'name': b'Foo'}
于 2019-02-17T12:17:40.610 回答
1

不幸的是,这段代码对我不起作用,因为一些结构成员是“指针”类型,它导致在字典中存储“无”。

我是一个 Python 菜鸟,但也许检查模块将是另一个起点,也是打印“简单”数据的更短方法。然后我们将迭代结果以展开数据结构。

例如以下示例:

struct foo {
int a;
char b[10];
};

使用 inspect.getmembers( obj ) 我有以下结果:

[('a', 10), ('b', <cdata 'char[10]' 0x7f0be10e2824>)]
于 2018-04-25T12:48:47.100 回答
0

你的代码很好。

即使 CFFI 中有内置方式,也不是您需要的。实际上,您可以说出另一个 cdataffi.new("foo_t*", {'p': p1})在哪里p1,但您不能递归地传递包含更多字典的字典。在相反的方向上也是如此:您会得到一个将字段名称映射到“值”的字典,但值本身无论如何都会是更多的 cdata 对象,而不是递归更多的字典。

于 2013-12-08T21:50:18.130 回答