我有一个用 Rust 编写的 C FFI,src/lib.rs如下所示:
// compile with $ cargo build
extern crate libc;
use self::libc::{size_t, int32_t};
use std::cmp::min;
use std::slice;
#[no_mangle]
pub extern "C" fn rle_new(values_data: *const int32_t, values_length: size_t) -> *mut Rle {
let values = unsafe { slice::from_raw_parts(values_data, values_length as usize).to_vec() };
return Box::into_raw(Box::new(Rle::new(values)));
}
#[no_mangle]
pub extern "C" fn rle_free(ptr: *mut Rle) {
if ptr.is_null() {
return;
}
unsafe {
Box::from_raw(ptr);
}
}
#[no_mangle]
pub extern "C" fn rle_values_size(rle: *mut Rle) -> int32_t {
unsafe { (*rle).values.len() as i32 }
}
#[no_mangle]
pub extern "C" fn rle_values(rle: *mut Rle) -> *mut int32_t {
unsafe { &mut (*rle).values[0] }
}
#[derive(Debug, PartialEq)]
pub struct Rle {
pub values: Vec<i32>,
}
impl Rle {
pub fn new(values: Vec<i32>) -> Self {
return Rle { values: values };
}
}
Run Code Online (Sandbox Code Playgroud)
这是我在项目基础文件夹中的 Cargo.toml:
[package]
name = "minimal_example"
version = "0.1.0"
authors = ["Dumbass"]
[dependencies]
libc = "0.2.16"
[lib]
crate-type = ["dylib"] # you might need a different type on linux/windows ?
Run Code Online (Sandbox Code Playgroud)
这是调用 Rust 的 Python 代码,也放在基本文件夹中:
[package]
name = "minimal_example"
version = "0.1.0"
authors = ["Dumbass"]
[dependencies]
libc = "0.2.16"
[lib]
crate-type = ["dylib"] # you might need a different type on linux/windows ?
Run Code Online (Sandbox Code Playgroud)
我有充分的理由相信 C 代码是正确的,因为rle_values_size和rle_values引用同一个对象,即结构中的 Rust 向量,并且该rle_values_size函数有效。
但是,当我尝试取消引用由 给出的指针rle_values并将其作为数组读取时,我得到了段错误。
我已经尝试了我在 Stack Overflow 上找到的每一个代码片段的排列,但它出现了段错误。
为什么会崩溃?我究竟做错了什么?
我添加了 Rust 标签,因为我可能会以错误的方式获取向量的地址。
附言。如果有人也知道如何将它直接读入一个 numpy 数组,我也会赞成。
本cast应该是第一个警告信号。为什么你必须从类型转换为应该是相同的类型?这是因为有简单的错别字:
lib.rle_values.restype = POINTER(c_int32)
lib.rle_values_size.restype = c_int32
Run Code Online (Sandbox Code Playgroud)
请注意,它应该是restype,而不是restypes。
def __str__(self):
values_size = lib.rle_values_size(self.obj)
print(values_size, "values_size")
values_pointer = lib.rle_values(self.obj)
print("values_pointer:", values_pointer)
thing = values_pointer[:values_size]
return str(thing)
Run Code Online (Sandbox Code Playgroud)
最好使用as_mut_ptr:
#[no_mangle]
pub extern "C" fn rle_values(rle: *mut Rle) -> *mut int32_t {
let mut rle = unsafe { &mut *rle };
rle.values.as_mut_ptr()
}
Run Code Online (Sandbox Code Playgroud)
运行该程序似乎有效:
$ LD_LIBRARY_PATH=$PWD/target/debug/ python3 main.py
new
30 values_size
values_pointer: <__main__.LP_c_int object at 0x10f124048>
[1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2]
Run Code Online (Sandbox Code Playgroud)
我还建议:
cint。不指定 for 的返回类型free可能不是一个好主意,因为它应该是void。unsafe块的范围缩小到不安全的部分和确保它实际上安全的代码。说到这里,您可以检查NULL每个函数中的指针。
#[no_mangle]
pub extern "C" fn rle_values_size(rle: *mut Rle) -> int32_t {
match unsafe { rle.as_ref() } {
Some(rle) => rle.values.len() as i32,
None => 0,
}
}
#[no_mangle]
pub extern "C" fn rle_values(rle: *mut Rle) -> *mut int32_t {
match unsafe { rle.as_mut() } {
Some(mut rle) => rle.values.as_mut_ptr(),
None => ptr::null_mut(),
}
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
522 次 |
| 最近记录: |