Примечание. Этот ответ немного устарел, он предлагает вам использовать другой макет данных для кода C.
Вы можете изменить свою структуру C на что-то вроде этого:
typedef struct point {
int x;
int y;
} point;
typedef struct points {
size_t len;
point points[];
} points;
Это называется гибкий элемент массива , очень приятная и неизвестная функция C, которая позволяет вам сделать только одно выделение. Типичный вариант использования соответствует вашему случаю.
Кроме того, даже в C int
не подходит тип для представления размера, вы должны использовать size_t
.
Вы также должны использовать bindgen для обработки FAM, это обеспечивает полезную функцию, такую как as_slice()
.
С учетом следующего кода C:
typedef struct point {
int x;
int y;
} point;
typedef struct points {
size_t len;
point points[];
} points;
struct points *new_points(size_t len) {
struct points *points = malloc(sizeof *points + sizeof *points->points * len);
if (points) {
points->len = len;
}
return points;
}
В настоящее время генерируется:
#[repr(C)]
#[derive(Default)]
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
impl<T> __IncompleteArrayField<T> {
#[inline]
pub fn new() -> Self {
__IncompleteArrayField(::std::marker::PhantomData)
}
#[inline]
pub unsafe fn as_ptr(&self) -> *const T {
::std::mem::transmute(self)
}
#[inline]
pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
::std::mem::transmute(self)
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
::std::slice::from_raw_parts(self.as_ptr(), len)
}
#[inline]
pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
#[inline]
fn clone(&self) -> Self {
Self::new()
}
}
impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct point {
pub x: ::std::os::raw::c_int,
pub y: ::std::os::raw::c_int,
}
#[repr(C)]
#[derive(Debug)]
pub struct points {
pub len: usize,
pub points: __IncompleteArrayField<point>,
}
extern "C" {
pub fn new_points(len: usize) -> *mut points;
}
Некоторые строки пропущены
С этим переплетом вы можете сделать в Rust side:
#[no_mangle]
pub fn print_points(points: &points) {
for point in unsafe { points.points.as_slice(points.len) } {
println!("{:?}", point);
}
}
as_ptr()
позволяют избежать накладных расходов на создание временного среза, так что делайте как хотите.
А на стороне C:
#include <stdlib.h>
typedef struct point {
int x;
int y;
} point;
typedef struct points {
size_t len;
point points[];
} points;
struct points *new_points(size_t len);
void print_points(struct points *points);
int main(void) {
struct points *points = new_points(42);
int x = 0;
for (size_t i = 0; i < points->len; i++, x++) {
points->points[i] = (struct point){ .x = x, .y = -x};
}
print_points(points);
}
Однако помните, что ничто из этого не является гарантией, вы можете столкнуться с совершенно неопределенным поведением, будьте осторожны.
#[derive(Debug)]
#[repr(C)]
pub struct points {
count: c_int,
array_of_points: [point],
}
Вы сообщаете компилятору, что array_of_points
является допустимым фрагментом, но это не так, ваш код:
#[no_mangle]
pub fn do_something(all_points: &points) {
for i in 0..all_points.count {
let crr_point = &all_points.array_of_points[i as usize];
println!("{:?}", crr_point);
}
}
абсолютно неопределенное поведение. Я не думаю, что есть способ создать такую вещь на стороне C, Я не нашел один .