将Rust变量传递给希望能够对其进行修改的C函数 [英] Passing a Rust variable to a C function that expects to be able to modify it
问题描述
我正在编写一个安全的Rust层,通过它我可以从Rust中的C库调用函数.我已经使用 rust-bindgen 生成了不安全的绑定,但是我对此有些困惑在传递指针方面,Rust和C的工作方式之间的差异.
I'm writing a safe Rust layer with which I can call functions from a C library in Rust. I've generated the unsafe bindings using rust-bindgen, but I'm getting a little confused on the differences between how Rust and C work with regards to passing pointers.
C函数如下所示:
bool imeGet(unsigned char address, int *value);
它将读取address
处的I2C传感器,并将结果存储在value
中,并在成功后返回TRUE
.
It reads an I2C sensor at address
, stores the result in value
, and returns TRUE
on success.
Bindgen具有Rust功能,如下所示:
Bindgen has the Rust function looking like this:
pub fn imeGet(address: ::std::os::raw::c_uchar,
value: *mut ::std::os::raw::c_int) -> bool;
我的安全呼叫者当前如下所示:
And my safe caller looks like this currently:
pub fn ime_get(addr: u8) -> i32 {
let v: &mut i32 = 0;
unsafe {
imeGet(addr, v);
*v
}
}
由于= 0
,此代码无法编译.当我没有那个时,编译器会抱怨v
可能没有初始化.我的意图是在此函数中处理成功,并仅返回i32
值.
This code doesn't compile because of the = 0
. When I didn't have that, the compiler complained about v
possibly not having been initialized. My intent is to handle the success within this function, and just return the i32
value.
如何处理*mut c_int
参数的行为?我试图将v
声明为引用,并返回其取消引用的值(如上所述),但这不起作用.我也尝试只返回v
,但是我真的不希望返回值保持可变.
How do I handle the behavior of the *mut c_int
argument? I tried to declare v
as a reference and return its dereferenced value (above), but that doesn't work. I also tried to just return v
, but I don't really want the return value to stay mutable.
我对Rust还是很陌生,但是我在C语言方面确实有不错的背景,这可能是我感到困惑的原因.
I'm pretty new to Rust, but I do have a decent background in C, which may be my source of confusion.
推荐答案
但是我确实有不错的C背景
but I do have a decent background in C
Rust代码在道德上等同于:
The moral equivalent of your Rust code is:
int *v = NULL;
imeGet(addr, v);
*v
这将出现错误,因为C代码可能会取消引用v
来存储值,除非您传入了NULL,所以它很有可能繁荣起来.
This will have an error because the C code is likely going to dereference that v
to store the value in, except you've passed in a NULL, so it's more likely to go boom.
您需要为该值创建存储,然后为该函数提供对该存储的引用:
You need to create storage for the value, then provide a reference to that storage to the function:
fn ime_get(addr: u8) -> i32 {
let mut v = 0;
unsafe { imeGet(addr, &mut v) };
v
}
针对任何指针类型的解决方案都使用 ptr::null_mut
:
The solution for any pointer type uses ptr::null_mut
:
unsafe {
let mut v = std::ptr::null_mut();
takes_a_pointer_pointer(addr, &mut v);
v
}
任何类型的通用解决方案都使用 mem::MaybeUninit
:
The general solution for any type uses mem::MaybeUninit
:
unsafe {
let mut v = std::mem::MaybeUninit::uninit();
takes_a_value_pointer(addr, v.as_mut_ptr());
v.assume_init()
}
为了完整性,您应该检查返回值:
For completeness, you should be checking the return value:
fn ime_get(addr: u8) -> Option<i32> {
let mut v = 0;
let success = unsafe { imeGet(addr, &mut v) };
if success {
Some(v)
} else {
None
}
}
Rust和C在传递指针方面的区别.
the differences between how Rust and C work with regards to passing pointers.
在这个级别上确实没有任何东西.
There really aren't any, at this level.
这篇关于将Rust变量传递给希望能够对其进行修改的C函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!