Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如果将结构移动到不同的位置,锈迹是否有任何特征会得到通知?_Rust_Embedded_Move_Ffi - Fatal编程技术网

Rust 如果将结构移动到不同的位置,锈迹是否有任何特征会得到通知?

Rust 如果将结构移动到不同的位置,锈迹是否有任何特征会得到通知?,rust,embedded,move,ffi,Rust,Embedded,Move,Ffi,在微控制器的Rust和C代码的混合中,我有一个Rust数据结构,我必须让程序的C部分知道它。我让它工作了 pub struct SerialPort { // ... some attributes ... } 我试图重构Rust代码,并希望在一个函数中生成Rust结构,该函数也在我的C代码中注册回调 pub fn setup_new_port() -> SerialPort { let port = SerialPort::new(); port.registe

在微控制器的Rust和C代码的混合中,我有一个Rust数据结构,我必须让程序的C部分知道它。我让它工作了

pub struct SerialPort {
    // ... some attributes ...
}
我试图重构Rust代码,并希望在一个函数中生成Rust结构,该函数也在我的C代码中注册回调

pub fn setup_new_port() -> SerialPort {
    let port = SerialPort::new();
    port.register_with_c_code();
    port
}
这不起作用,因为当函数返回时,Rust会将类型为
SerialPort
的变量的内存内容移动到不同的位置。C代码中注册的地址指向
setup\u new\u port()
的堆栈帧(现在已释放),而它被移动到调用方的堆栈帧,因此我的C代码将访问无效地址

我是否可以实现在移动发生时收到通知的任何特性?我可以在trait的实现中调整C代码中注册的地址


我知道我可以通过在堆上分配我的结构来防止移动的发生,但我希望避免这种情况,因为代码在微控制器上运行,动态内存分配可能并不总是存在。

不,设计上是这样。

Rust是专门设计的,没有所谓的移动构造函数,在Rust中,移动是按位复制,允许进行许多优化:

  • 例如使用C
    memcpy
    realloc
  • 基于以下事实的优化:没有
    恐慌可以在移动过程中调用
实际上,在C++中有一些改进这种设计的建议(代码> iSeRealabase),性能是主要驱动程序。
那又怎样?

Mutex
Do!也就是说,
Box
任何不应移动的内容,并将其隔离在不透明的
struct
中,以便任何人都无法将内容移出框中

如果堆分配不可用。。。然后,您可能需要查看或借用该结构。借用的东西不能移动。

我看到的唯一解决方案(我不是说它是唯一的解决方案)是在堆栈中放置一个竞技场,或另一种占位符:

#[derive(Default)]
pub struct SerialPort {
    _dummy: i32,
}

pub fn setup_new_port(placeholder: &mut Option<SerialPort>) -> &SerialPort {
    let port = SerialPort::default();
    std::mem::replace(placeholder, Some(port));
    let port = placeholder.as_ref().unwrap();
    println!("address: {:p}", port);
    //port.register_with_c_code();
    port
}

fn main() {
    let mut placeholder = None;

    let port = setup_new_port(&mut placeholder);
    println!("address: {:p}", port);
}
#[派生(默认)]
发布结构串行端口{
_假人:i32,
}
发布fn设置\新\端口(占位符:&mut选项)->&SerialPort{
let port=SerialPort::default();
std::mem::replace(占位符,一些(端口));
让端口=占位符.as_ref().unwrap();
println!(“地址:{:p}”,端口);
//使用_c_代码()注册_;
港口
}
fn main(){
让mut占位符=无;
let port=setup\u new\u port(&mut占位符);
println!(“地址:{:p}”,端口);
}
这两个
println行打印相同的值

我在互联网上搜索了一下,想在堆栈中找到一个装有竞技场的板条箱,但到目前为止什么也没找到。

我想把它分开。 我会在某个地方(堆栈上)创建一个Serialport实例,然后调用
register\u with\u c\u code()
。另外,我将
impl Drop
用于Serialport,这样当Serialport超出范围时,c_代码将被分离


对于您的Serialport接口,我不接受任何移动,只接受(可变)引用。

您有堆吗?@Boiethios在系统上,我当前正在实现这个,我有。但情况并非总是如此,因此我更愿意避免使用堆。(结构不是很大,也不需要很快。所以在我的用例中移动它是可以的。)说清楚,这正是C所做的。这仅仅是因为您使用的是FFI和原始指针,所以问题甚至出现在Rust中。如果您的FFI函数使用了生存期(这没有意义),Rust编译器会这样做。@Shepmaster感谢您的澄清,但我并没有抱怨Rust。事实上,这很有道理。但你所说的“C到底做了什么”是什么意思?我从未见过C中的移动语义。在C中,您将在
setup\u new\u port
的堆栈框架中创建
SerialPort
结构,将对它的引用传递给
register\u with\u C\u code
,然后通过退出函数立即使引用无效。这就是这里发生的事情,因为您使用的是原始指针。“移动语义”存在于C和C++中,RIST只允许编译器帮助你。我想我暂时还是用堆吧。其他一切似乎都会使代码变得更复杂,但到目前为止还没有必要。
mem::forget
可以在不调用
drop
的情况下使用分配给堆栈的
Serialport
,这可能会导致内存不安全。