问题描述
我有C ++代码,该代码使用数据调用Rust代码。它知道将数据发送到哪个对象。这是C ++回调的Rust函数的示例:
extern "C" fn on_open_vpn_receive(
instance: Box<OpenVpn>,data: *mut c_uchar,size: *mut size_t,) -> u8
它以Box
的形式接收指针,因此我创建了一个函数openvpn_set_rust_parent
,用于设置C ++必须回调的对象。该对象是指向自身的指针。我正在使用Pin
,因此Box
不会重新分配到其他地方,从而使C ++调用无效地址。
impl OpenVpn {
pub fn new() -> Pin<Box<OpenVpn>> {
let instance = unsafe { interface::openvpn_new(profile.as_ptr()) };
let o = OpenVpn { instance: instance };
let p = Box::pin(o);
unsafe {
interface::openvpn_set_rust_parent(o.instance,p.as_ptr());
};
p
}
}
签名:
pub fn openvpn_set_rust_parent(instance: *mut OpenVpnInstance,parent: *mut OpenVpn)
我不知道如何将p
转换为*mut OpenVpn
以传递给C ++。我的主意好吗?我认为Pin
的用法在这里很好,而且我认为这是从C ++调用对象的好方法。
解决方法
没关系。 Pin
并不是一种强力魔术,它会迫使您的价值永不动摇。的确,它归结为措辞强硬的文档和一些指南,可防止您在安全的Rust代码之内做坏事。 Pin
可能会受到不安全代码(包括任何FFI代码)的规避。
在您的Rust代码中包含Pin
可能会帮助您保持Rust代码的准确性和有效性,但是添加它对于从其他语言调用Rust来说没有任何用处。
Pin
is defined和repr(transparent)
一样,这意味着只要可以在FFI中安全使用内部类型,就可以在FFI签名中使用它:
#[stable(feature = "pin",since = "1.33.0")]
#[lang = "pin"]
#[fundamental]
#[repr(transparent)]
#[derive(Copy,Clone)]
pub struct Pin<P> {
pointer: P,}
我正在使用
Pin
,因此Box
不会重新分配到其他地方,从而使C ++调用无效地址。
Pin
不这样做, Box
不这样做。装箱时,将值移到堆中。 Box
本身只是一个指针。指针的地址 将移动,但是堆中的数据 的地址将不会移动。
请注意,即使0x55..30
本身已经移动,打印的第二个地址(堆上的Box
也是一样)
fn main() {
let a = 42;
let b = Box::new(a);
println!("{:p}",&b); // 0x7ffe3598ea80
println!("{:p}",&*b); // 0x556d21528b30
let c = b;
println!("{:p}",&c); // 0x7ffe3598ea88
println!("{:p}",&*c); // 0x556d21528b30
}
另请参阅: