Как создать структуру в 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. Чтение в стандартных заголовках библиотеки не рекомендуется.

Другие вопросы по тегам