C文件:
typedef struct point {
int x;
int y;
} point;
typedef struct points {
int count;
point *array_of_points;
} points;
锈文件:
#[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);
}
}
在我的C文件中,我分配了很多结构点并将其添加到array_of_points
,然后调用do_something
函数。
如何在Rust中获得array_of_points
中的每个点?
我在Rust中定义array_of_points
数组的方式正确吗?
运行它时,会出现以下奇怪结果:
point { x: 0, y: -952095696 }
point { x: 32674, y: 101 }
以此类推。
答案 0 :(得分:4)
这是不确定的行为。在该类型的Rust版本中,类型为array_of_points
的成员point*
被转换为Rust大小未定的切片{{1} },这既不等效也不兼容。通过添加类型为[point]
的成员,您建议[point]
在其第一个成员point
之后紧随其后的point
个对象具有可变数量。这也使count
成为未调整大小的类型(或动态调整大小的类型)。
C中points
的内存布局应为:
points
但是Rust的定义是这样的:
[ int, point* ]
|
-->[ point, point, ...] // dynamically allocated
[ int, point, point, ... ] // unknown compile time size
中的成员需要使用原始指针进行定义:
points
然后#[derive(Debug)]
#[repr(C)]
pub struct points {
count: c_int,
array_of_points: *mut point,
}
应该通过偏移量取消指针的引用以获取每个点:
do_something
或从#[no_mangle]
pub fn do_something(all_points: &points) {
for i in 0..all_points.count {
unsafe {
let crr_point = &*all_points.array_of_points.offset(i as isize);
println!("{:?}", crr_point);
}
}
}
中的给定部分中构造适当的Rust切片:
points
请注意在任何一种情况下您如何 #[no_mangle]
pub fn do_something(all_points: &points) {
let point_array = unsafe {
std::slice::from_raw_parts(all_points.array_of_points, all_points.count as usize)
};
for crr_point in point_array {
println!("{:?}", crr_point);
}
}
进行编码。
另请参阅:
答案 1 :(得分:0)
注意:这个答案有点不对,建议您为C代码使用其他数据布局。
您可以将C结构更改为以下形式:
typedef struct point {
int x;
int y;
} point;
typedef struct points {
size_t len;
point points[];
} points;
这称为flexible array member,这是一个非常不错的未知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方面进行操作:
#[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端创建这样的东西,我没找到。