C file:
typedef struct point {
int x;
int y;
} point;
typedef struct points {
int count;
point *array_of_points;
} points;
Rust file:
#[derive(Debug)]
#[repr(C)]
pub struct point {
x: c_int,
y: c_int,
}
#[derive(Debug)]
#[repr(C)]
pub struct points {
count: c_int,
array_of_points: [point],
}
#[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);
}
}
In my C file, I allocate a lot of struct point and add them to array_of_points
, then I call the do_something
function.
How do I get each single point in array_of_points
in Rust?
Is way I defined the array_of_points
array in Rust correct?
When I run it, this strange outcome appears:
point { x: 0, y: -952095696 }
point { x: 32674, y: 101 }
and so on.
Note: This answer is a little off, it propose you to use an another data layout for your C code.
You could change your C structure to something like this:
This is called a flexible array member, a very nice and unknown C feature, that allows you to only make one allocation. The typical use-case matches your case.
Also, even in C
int
is not a suitable type to represent a size, you should usesize_t
.You should also use bindgen to handle FAM, it's provide useful function like
as_slice()
.Given the following C code:
It currently generate:
Some lines omitted
With this binding you can do in Rust side:
as_ptr()
allow to avoid the overhead of creating a temporary slice, so do as you like.And in the C side:
However remember that nothing of this is guarantee, you could run into a complete undefined behavior, be careful.
You tell to the compiler that
array_of_points
is a valid slice, but it's not so your code:is completely undefined behavior. I don't think there is a way to create such thing in C side, I didn't find one.
That is undefined behaviour. In the Rust version of that type, the member
array_of_points
, of typepoint*
, was translated to a Rust unsized slice[point]
, which is not equivalent nor compatible. By adding a member of type[point]
, you are suggesting thatpoint
has a variable number of trailingpoint
objects directly after its first membercount
. This also makespoints
an unsized type (or dynamically sized type).The memory layout of
points
in C should be the following:But that Rust definition was making this:
The member in
points
needs to be defined with a raw pointer:Then
do_something
should either dereference the pointer by an offset to retrieve each point:Or construct a proper Rust slice out of the given parts in
points
:Note how you need
unsafe
code in any of these cases.See also: