Ваш вопрос немного неясен, но я думаю, что, если я вас правильно понял, вы путаете две вещи и в результате получаете в результате темный переулок.
В C, динамический размермассив, как вы, наверное, знаете, идентифицируется двумя вещами:
- Его начальная позиция в виде указателя
- Его длина
Ржавчина следует тому жеусловное обозначение - Vec<_>
, ниже капота, имеет ту же структуру (ну, почти. У него тоже есть емкость, но это не относится к делу).
Передача в штучной упаковке вектора сверху *Указатель 1015 * не только излишний, но и крайне неразумный. Привязки FFI могут быть умными, но они недостаточно умны, чтобы в большинстве случаев иметь дело со сложным типом в штучной упаковке.
Чтобы решить эту проблему, мы упростим ваши привязки. Я добавил один элемент в struct S
, чтобы показать вам, как он работает. Я также очистил вашу границу FFI:
#[repr(C)]
#[no_mangle]
pub struct S {
foo: u8
}
#[repr(C)]
pub struct s_arr {
arr: *mut S,
n: usize,
cap: usize
}
// Retrieve the vector back
pub unsafe extern "C" fn recombine_s_arr(ptr: *mut S, n: usize, cap: usize) -> Vec<S> {
Vec::from_raw_parts(ptr, n, cap)
}
#[no_mangle]
pub unsafe extern "C" fn gen_s_arr() -> s_arr {
let mut many_s: Vec<S> = Vec::new();
let output = s_arr {
arr: many_s.as_mut_ptr(),
n: many_s.len(),
cap: many_s.capacity()
};
std::mem::forget(many_s);
output
}
. Таким образом, cbindgen возвращает ожидаемые определения заголовка:
typedef struct {
uint8_t foo;
} so58311426S;
typedef struct {
so58311426S *arr;
uintptr_t n;
uintptr_t cap;
} so58311426s_arr;
so58311426s_arr gen_s_arr(void);
Это позволяет нам вызывать gen_s_arr()
из C илиРастрите и извлеките структуру, которую можно использовать в обеих частях границы FFI (so58311426s_arr
). Эта структура содержит все, что нам нужно, чтобы иметь возможность изменять наш массив S
(ну, so58311426S
в соответствии с cbindgen).
При прохождении через FFI вам необходимо убедиться в нескольких простых вещах:
- Вы не можете передавать необработанные блоки или не примитивные типы;Вам почти повсеместно потребуется преобразовать в набор указателей или изменить свои определения, чтобы приспособить их (как я сделал здесь)
- Вы наиболее определенно не пропускают необработанные векторы. В лучшем случае вы передаете срез, так как это примитивный тип (см. Пункт выше).
- Вы обязательно
std::mem::forget()
делаете все, что не хотите освобождать, и не забывайте освобождать его. или измените его где-нибудь еще.
Я отредактирую этот вопрос через час;У меня есть самолет, чтобы сесть на него. Дайте мне знать, если что-то из этого потребует разъяснений, и я доберусь до него, как только окажусь в нужной стране: -)