如何在python cffi中实例化一个结构?

时间:2017-06-14 17:32:41

标签: python python-cffi cffi

我正在尝试使用Python cffi库实例化一个struct。我想从我自己的.h文件以及标准库中的结构实例化一个结构。

import datetime
import os
from cffi import FFI

clib = None

script_path = os.path.dirname(os.path.realpath(__file__))

ffi = FFI()
with open(os.path.join(script_path, 'myheader.h'), 'r') as myfile:
    source = myfile.read()
    ffi.cdef(source)
clib = ffi.dlopen('mylib')

# these all fail
ffi.new("struct tm")
ffi.new("struct tm[]", 1)
ffi.new("struct tm *")
ffi.new("struct mystruct")

2 个答案:

答案 0 :(得分:1)

ffi.new("struct mystruct")不正确,您的意思可能是ffi.new("struct mystruct *")

struct tm很可能未在cdef()中定义,即在您的情况下,myheader.h内未提及。您需要先在cdef()中定义它,然后才能使用它,即使它位于一个通用的标准标题中。

您可能最好使用set_source()(API模式),因为您可以使用struct tm的近似定义,例如类似的东西:

struct tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    ...;       /* literally a "..." here */
};

如果您使用dlopen()(ABI模式),则必须使用与平台标头中完全相同的声明。结果不太便携。

答案 1 :(得分:0)

TL; DR Armin可能是正确的(并且绝对是此处的专家)。如果tm是ctime的结构,则需要对其进行定义。如果它是您自己的结构,但未在myheader.h中定义,则需要添加定义或将相关标头读取到source字符串中。如果其他所有方法均失败,则可能需要typedef

这行不通:

ffi.new("struct tm")

这应该有效:

ffi.new("struct tm[]", 1)

但是这个看起来更好:

ffi.new("struct tm *")

但是,这对我来说没有意义:

ffi.new("struct mystruct")

如果将tm定义为typedef,则不需要struct。如果将ctime tm重新定义为mystruct,则此处需要“ *”。如果它是typedef,则不能指定struct,但是可以使用它:

ffi.new("mystruct *")

我无法使用不是typedef的结构。如果Armin没有其他暗示,我会声明不支持它们。也许您遇到了同样的问题。

如果您对头文件和结构名称有任何控制权或话语权,无论如何,我强烈建议对结构进行typedef定义。这是C语言中结构的通用做法。

typedef struct tm {
/* struct internals here */
} tm; // not recommended using this short of a name though

除非tm是代码的完全核心,以至于其含义总是显而易见的,强烈建议在使用typedef时使用更具描述性的名称。这成为全局定义,因此也有助于避免发生任何冲突,例如ctime结构tm。这样会更好:

typedef struct {
/* struct internals here */
} taskmaster; // or something similarly descriptive, having nothing else to go on I assume 'tm' is referring to my favorite UK panel show and not ctime

您也可以像在这里一样完全丢弃tm。使用typedef时仅需要最终类型名称。

无论如何,关键是typedef不要在声明中使用struct

mytm = ffi.new("tm *") # again, this level of abbreviation is not recommended

mytm = ffi.new("taskmaster *")

还请记住,CFFI不理解指令,例如#include。因此,如果myheader.h没有定义struct tm而是将其从另一个文件(例如ctime)中拉出,则您需要专门定义它,或者(读取并)将所有感兴趣的头文件添加到{ {1}}字符串用于cdef调用。建议不要 阅读标准的lib标头。