0

我正在尝试使用 Python cffi 库实例化一个结构。我想从我自己的 .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")
4

2 回答 2

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 模式),那么您必须使用与平台标题中完全相同的声明。结果是不太便携。

于 2017-06-15T08:27:48.210 回答
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 没有另外暗示,我会宣布它们不受支持。也许你遇到了同样的问题。

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

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

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

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)中提取它,您要么需要专门定义它,要么(读取并)将所有感兴趣的头文件添加到您的source字符串中以进行 cdef 调用。建议阅读标准库头文件。

于 2020-10-29T00:28:30.413 回答