假设我有以下Rust库:
// lib.rs
#![crate_type = staticlib]
#[no_mangle]
pub extern fn do_something(number: i32) {
// something
}
#[no_mangle]
pub extern fn do_something_else(collection: &Vec<i32>) {
// something
}
Run Code Online (Sandbox Code Playgroud)
我知道,do_something要从C 调用,我只需要声明一个extern函数int32_t,但是可以调用do_something_else吗?如果是这样,怎么样?
你可以,但更好的问题是应该吗?
由于你不能构造一个Vecfrom C,你必须在Rust中构造它,然后返回一个指向C的指针.C代码将拥有指向Vec它的指针,然后在调用时将其传回do_something_else.
然后就是你无法真正修改VecC语言的问题,除了创建镜像所有Rust方法的新FFI方法.
您也可能不应该使用,&Vec<i32>因为Rust引用保证不为NULL,并且从C调用时没有任何强制执行.最好采用a *const Vec<i32>,断言它是非NULL并将其转换为引用.
您可能希望通过FFI边界接受C数组.C数组是一个指针和一个长度,所以你接受这两个并重新构建一个Rust 切片(因为你不拥有该数组):
use std::slice;
pub extern fn do_something_else(p: *const i32, len: libc::size_t) {
let slice = unsafe {
assert!(!p.is_null());
slice::from_raw_parts(p, len)
};
}
Run Code Online (Sandbox Code Playgroud)
与Rust FFI Omnibus的强制性链接.
如果你真的需要做你所问的话,它可能看起来像这样:
extern crate libc;
#[no_mangle]
pub extern fn make_vec() -> *mut Vec<i32> {
Box::into_raw(Box::new(Vec::new()))
}
#[no_mangle]
pub extern fn add_number(vec: *mut Vec<i32>, val: libc::int32_t) {
let vec = unsafe {
assert!(!vec.is_null());
&mut *vec
};
vec.push(val);
}
#[no_mangle]
pub extern fn print_vec(vec: *const Vec<i32>) {
let vec = unsafe {
assert!(!vec.is_null());
&*vec
};
println!("{:?}", vec);
}
#[no_mangle]
pub extern fn drop_vec(vec: *mut Vec<i32>) {
unsafe {
assert!(!vec.is_null());
Box::from_raw(vec);
}
}
Run Code Online (Sandbox Code Playgroud)
并且会像(未经测试)一样使用:
// Add extern declarations
int main(int argc, char *argv[]) {
void *v = make_vec(); // Use a real typedef here
add_number(v, 42);
print_vec(v);
drop_vec(v);
}
Run Code Online (Sandbox Code Playgroud)
你想在valgrind下运行它,以确保我没有做任何愚蠢的记忆.
| 归档时间: |
|
| 查看次数: |
1522 次 |
| 最近记录: |