Pointers 如何将Rust结构的引用/指针传递给C ffi接口? 我想做什么

Pointers 如何将Rust结构的引用/指针传递给C ffi接口? 我想做什么,pointers,struct,rust,ffi,rust-cargo,Pointers,Struct,Rust,Ffi,Rust Cargo,我已经构建了一个Rust接口,我想通过C(或C#与之交互,但这并不重要)。因为似乎不可能让C访问Rust结构,所以我正在尝试构建一些可以调用的包装函数,这些函数将在Rust中创建结构,调用结构的函数,并最终手动从内存中释放结构 为了做到这一点,我想我应该将指向在init函数中创建的结构实例的指针传递回C(或C#,并将其临时存储为IntPtr)。然后,当我调用其他函数时,我会再次将指针传递给Rust,取消引用它,并在取消引用的结构上调用适当的函数,在过程中对其进行变异 我知道我将不得不使用不安全的

我已经构建了一个Rust接口,我想通过C(或C#与之交互,但这并不重要)。因为似乎不可能让C访问Rust结构,所以我正在尝试构建一些可以调用的包装函数,这些函数将在Rust中创建结构,调用结构的函数,并最终手动从内存中释放结构

为了做到这一点,我想我应该将指向在
init
函数中创建的结构实例的指针传递回C(或C#,并将其临时存储为
IntPtr
)。然后,当我调用其他函数时,我会再次将指针传递给Rust,取消引用它,并在取消引用的结构上调用适当的函数,在过程中对其进行变异

我知道我将不得不使用不安全的代码来做这件事,我对此很满意。我可能还应该指出,我对Rust中的终身管理知之甚少,很可能,我所尝试的是不可能的,因为在某个地方很容易产生一个松散的指针。在这种情况下,我想知道我需要如何调整我的方法,因为我认为我不是第一个试图从C中变异某种状态的人

我首先尝试的是什么 因此,首先,我确保输出正确的库,并向其中添加本机函数。在Cargo.toml中,我将lib类型设置为:

[lib]
板条箱类型=[“cdylib”]
然后我创建了一些与结构交互的函数,并将它们公开如下:

#[无损坏]
pub extern fn init()->*mut MyStruct{
让mut struct_instance=MyStruct::default();
struct_instance.init();
将raw_pointer_mut=&mut struct_实例设置为*mut MyStruct;
返回原始指针;
}
#[没有损坏]
发布外部fn添加项(结构实例引用:*mut MyStruct){
不安全{
让struct\u instance=&mut*struct\u instance\u ref;
struct_instance.add_item();
}
}
正如您在
init
函数中看到的,我正在创建结构,然后返回(可变)指针

然后在
add_item
函数中取指针并使用它

现在我尝试测试这个实现,因为我对指针是否仍然有效有些怀疑。在另一个Rust模块中,我加载了.dll和.lib文件(我在Windows上,但这对问题不重要),然后相应地调用函数,如下所示:

fn main(){
不安全{
设struct_pointer=init();
添加项目(结构指针);
println!(“指针地址:{:?}”,结构指针);
}
}
#[link(name=“my_library.dll”)]
外行{
fn init()->*mut u32;
fn添加项目(结构参考:*mut u32);
}
发生了什么:我确实得到了一些内存地址输出,而且(因为我实际上在实际实现中创建了一个文件),我还可以看到函数按计划执行。但是,结构的字段似乎没有发生突变。它们基本上都是空的,在我调用
add\u item
函数(也不是在我调用
init
函数)之后,它们不应该是空的

那之后我做了什么 我在Rust中读了一些关于生命周期管理的内容,因此尝试使用
在堆上分配结构,如下所示:

#[无损坏]
pub extern fn init()->*mut框{
让mut struct_instance=MyStruct::default();
struct_instance.init();
让原始指针\u mut=&mut-Box::new(struct\u实例)作为*mut-Box;
返回原始指针;
}
#[没有损坏]
发布外部fn添加框(结构实例引用:*多框){
不安全{
让struct\u instance=&mut*struct\u instance\u ref;
struct_instance.add_box();
}
}
不幸的是,结果与上述相同

补充资料 我想最好也包括
Struct
在原则上是如何构成的:

#[派生(默认)]
#[报告员(C)]
发布结构MyStruct{
//一些领域。。。
}
impl MyStruct{
///初始化一个新结构。
发布fn初始(&M自我){
self.some_field=无论什么;
}
///将项添加到结构中。
发布fn添加项目(
&莫特·赛尔夫,
可能有更多的数据:属于类型//显然,需要调整外部函数中的调用以适应该类型。。。
){
some_other_function(self);//调用Rust中的另一个函数,该函数将结构实例作为参数并对其进行变异。
}
}

铁锈具有强烈的腐蚀性。问问自己:谁拥有
MyStruct
实例?它是
struct\u实例
变量,其生存期是
init()
函数的作用域。因此,在
init()
返回后,实例将被删除,并返回一个无效指针

在堆上分配
MyStruct
将是解决方案,但不是以您尝试的方式:实例被移动到堆中,但是
包装绑定到同一个有问题的生存期,因此它会破坏堆分配的对象

一种解决方案是在删除框之前将堆分配的值从框中取出:

#[无损坏]
pub extern fn init()->*mut MyStruct{
让mut struct_instance=MyStruct::default();
struct_instance.init();
let box=box::i(结构\实例);
盒子::放入原始(盒子)
}
要在以后销毁该值,请使用创建一个新的拥有该值的
框,然后让该框在超出范围时释放其包含的值:

#[无损坏]
pub extern fn destroy(结构实例:*mut MyStruct){
不安全的{Box::from_raw(struct_instance);}
}
这似乎是一个常见的问题,因此可能有一个更惯用的解决方案。希望有更有经验的人会加入进来。

铁锈有很强的不稳定性