Как создать структуру в Python CFFI?
Я пытаюсь создать экземпляр структуры, используя библиотеку 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")
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), тогда вы должны вместо этого использовать точно такую же декларацию, как в заголовках вашей платформы. Результат менее портативный.
TL;DR Армин, вероятно, прав (и определенно является здесь экспертом). Если
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, вы не можете указать структуру, но вместо этого это будет работать:
ffi.new("mystruct *")
Мне не удалось заставить работать структуры, которые не
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), вам нужно либо определить его специально, либо (прочитать и) добавить все интересующие файлы заголовков в свой
source
строка для вызова cdef. Чтение в стандартных заголовках библиотеки не рекомендуется.