你可以,但最好的问题是应该你?
既然你不能在C构建一个Vec
,你必须建立它在锈,然后返回一个指向下的C代码将自己的指针Vec
,然后将其传回调用do_something_else
时。
然后存在的问题是,您无法真正修改C中的Vec
,除了创建新的FFI方法来镜像所有Rust方法。
你也可能不应该采取,因为锈病引用保证不为NULL,并没有什么强制执行,从C.调用时最好是采取*const Vec<i32>
,断言它的非NULL和将其转换为参考。
很可能您希望通过FFI边界接受C数组。 C数组的指针和长度,所以你会同时接受并重组防锈片(因为你没有自己的数组):
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)
};
}
强制性链接The 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);
}
}
,并会使用类似(未经测试):
// 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);
}
你想在valgrind下运行,以确保我没有做任何愚蠢的记忆方式。
我认为你可以将整数数组指针传递给C中的生锈函数,然后你可以使用矢量切片来完成操作。 – noshusan
@noshusan你的意思是做一些像'pub extern fn do_thing(slice:&[i32])'然后在C方声明它像'void do_thing(int32_t slice [])''? –
我不确定,但是你可以做一些像'pub extern fn do_thing(slice:* [i32])'这样的声明在c面,像'void do_thing(int32_t * slice [])'一样。这里你使用的是raw_pointer,所以你必须声明一个不安全的块。 – noshusan