我有使用数据调用 Rust 代码的 C++ 代码。它知道将数据发送到哪个对象。下面是 C++ 回调的 Rust 函数示例:
extern "C" fn on_open_vpn_receive(
instance: Box<OpenVpn>,
data: *mut c_uchar,
size: *mut size_t,
) -> u8
Run Code Online (Sandbox Code Playgroud)
它将指针作为 a 接收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
}
}
Run Code Online (Sandbox Code Playgroud)
签名:
pub fn openvpn_set_rust_parent(instance: *mut OpenVpnInstance, parent: *mut OpenVpn)
Run Code Online (Sandbox Code Playgroud)
我不知道如何转换p为*mut OpenVpn传递给C++。我的想法好吗?我认为Pin这里的用法很好,而且我认为这是从 C++ 调用对象的好方法。
没关系。Pin不是一种非常神奇的类型,它会迫使您的价值永不移动。真的,它归结为措辞强硬的文档和一些指导方针,可以防止您在安全的 Rust 代码中做坏事。Pin可以通过不安全代码(包括任何 FFI 代码)规避。
具有Pin您的锈代码中可能会帮助你保持防锈码准确和有效的,但它没有什么可补充从其他语言调用防锈的目的。
Pin定义为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,
}
Run Code Online (Sandbox Code Playgroud)
我正在使用,
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
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
| 归档时间: |
|
| 查看次数: |
300 次 |
| 最近记录: |