我有一个用Rust写的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 };
}
}
这是我的货物.toml在project base文件夹中:
^{pr2}$这是调用Rust的Python代码,也放在基本文件夹中:
import os
import sys, ctypes
from ctypes import c_char_p, c_uint32, Structure, POINTER, c_int32, c_size_t, pointer
class RleS(Structure):
pass
prefix = {'win32': ''}.get(sys.platform, 'lib')
extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')
libpath = os.environ.get("LD_LIBRARY_PATH", "target/debug") + "/"
libpath = libpath + prefix + "minimal_example" + extension
try:
lib = ctypes.cdll.LoadLibrary(libpath)
except OSError:
print("Library not found at " + libpath)
sys.exit()
lib.rle_new.restype = POINTER(RleS)
lib.rle_free.argtypes = (POINTER(RleS), )
lib.rle_values.argtypes = (POINTER(RleS), )
lib.rle_values.restypes = POINTER(c_int32)
lib.rle_values_size.argtypes = (POINTER(RleS), )
lib.rle_values_size.restypes = c_int32
class Rle:
def __init__(self, values):
values_length = len(values)
values_array = (c_int32 * len(values))(*values)
self.obj = lib.rle_new(values_array, c_size_t(values_length))
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
lib.rle_free(self.obj)
def __str__(self):
values_size = lib.rle_values_size(self.obj)
print(values_size, "values_size") # prints correct value
values_pointer = lib.rle_values(self.obj)
print("values_pointer:", values_pointer)
ar = ctypes.cast(values_pointer, ctypes.POINTER(ctypes.c_int32)).contents
print(ar) # segfaults!
rle = Rle([1, 1, 2] * 10)
print(rle)
我有充分的理由相信C代码是正确的,因为rle_values_size
和{rle_values_size
函数起作用。在
但是,当我试图取消引用rle_values
给出的指针并将其作为数组读取时,我得到了segfaults。在
我已经尝试过在堆栈溢出上找到的每一个代码片段的排列,但它总是出错。在
为什么会崩溃?我做错什么了?在
我添加了Rust标签,因为我可能会以错误的方式获取向量的地址。在
另外,如果有人也知道如何将这个直接读入numpy数组,我也会投赞成票。在
cast
应该是第一个警告标志。为什么要从类型转换为应该是同一类型的类型?这是因为有一些简单的打字错误:注意,它应该是}。在
^{pr2}$restype
,而不是{最好使用
as_mut_ptr
:运行程序似乎有效:
我还建议:
cint
。不为free
指定返回类型可能不是一个好主意,因为它应该是void
。在unsafe
块的范围缩小到不安全的部分和确保它实际上是安全的代码。在说到这里,您可以检查每个函数中的
NULL
指针。在相关问题 更多 >
编程相关推荐