首页 > 解决方案 > 使用类型 `[my_struct]` 是否是将 C 结构数组传递给 Rust 函数的正确方法?

问题描述

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 文件中,我分配了很多 struct point 并将它们添加到array_of_points,然后我调用该do_something函数。

我如何array_of_points在 Rust 中获得每个单点?

array_of_points在 Rust 中定义数组的方式是否正确?

当我运行它时,出现了这个奇怪的结果:

point { x: 0, y: -952095696 }   
point { x: 32674, y: 101 }   

等等。

标签: cstructrustffi

解决方案


那是未定义的行为。在该类型的 Rust 版本中, type 的成员array_of_pointspoint*转换为 Rust 未调整大小的 slice [point],这既不等价也不兼容。通过添加类型的成员[point],您建议在其第一个成员之后直接point具有可变数量的尾随point对象count。这也产生points了一个未调整大小的类型(或动态调整大小的类型)。

C中的内存布局points应该如下:

[ int, point* ]
           |
            -->[ point, point, ...] // dynamically allocated

但是那个 Rust 定义是这样的:

[ 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);
    }
}

请注意在任何这些情况下您如何需要代码。 unsafe

也可以看看:


推荐阅读