将Rust变量传递给希望能够对其进行修改的C函数 [英] Passing a Rust variable to a C function that expects to be able to modify it

查看:165
本文介绍了将Rust变量传递给希望能够对其进行修改的C函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个安全的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆