问题描述
我有一个 C 库,它具有 gpio 实现.有特定于目标的 gpio_type,每个 MCU 对 gpio_type 有不同的定义.库中的函数之一:
I have a C library, which has gpio implementation. There's gpio_type which is target specific, each MCU has different definition for gpio_type. One of the functions in the library:
void gpio_init(gpio_type *object, int32_t pin);
我想使用 C 库函数在 Rust 中编写 Gpio 对象的抽象.因此需要类似不透明指针类型的东西(在 C++ 中,我只需创建一个类型为:gpio_type 的成员变量).我想我会创建一个空的枚举(或结构),分配对象所需的空间并将其转换为匹配 C 层中的类型.
I want to write abstraction of Gpio object in Rust, using C library functions. Therefore need something like opaque pointer type (in C++ I would just create a member variable with type: gpio_type). I figured I would create an empty enum (or struct), allocate a space needed for the object and transmute it to match the type in C layer.
pub enum gpio_type {}
#[link(name = "gpio_lib", kind = "static")]
extern {
pub fn gpio_init(obj: *mut gpio_type, value: i32);
}
pub struct Gpio {
gpio : *mut gpio_type,
}
impl Gpio {
pub fn new(pin: u32) -> Gpio {
unsafe {
let mut gpio_ptr : &'static [u8; 4] = init(); // size of gpio in C is 4 bytes for one target, will be changed later to obtain it dynamically
let gpio_out = Gpio { gpio: transmute(gpio_ptr)};
gpio_init(gpio_out.gpio, pin);
gpio_out
}
}
}
这针对嵌入式设备,因此没有 std,没有 libc.我不想为 rust 中的每个目标重新定义 gpio_type(复制每个目标的 C 声明),寻找一些东西来为 C 将处理的对象分配内存.
This targets embedded devices, therefore no std, no libc. I don't want to redefine gpio_type for each target in rust (copy the C declaration for each target), looking for something to just allocate memory for the object which C will handle.
下面的代码片段根据反汇编生成指向地址 0 的指针.Gpio新方法的反汇编:
The following snippet below produces pointer to address 0 according to disassembly. Disassembly for Gpio new method:
45c: b580 push {r7, lr}
45e: 466f mov r7, sp
460: 4601 mov r1, r0
462: 2000 movs r0, #0
464: f000 fae6 bl a34 <gpio_init>
468: 2000 movs r0, #0
46a: bd80 pop {r7, pc}
知道为什么 462 是 0 吗?
Any ideas why 462 is 0 ?
推荐答案
这样的事情呢?给结构一个实际大小(在这种情况下,给它一个字节大小的固定大小数组),在堆上分配那个空间,然后把它当作一个原始指针.
What about something like this? Give the struct an actual size (in this case by giving it a fixed-size array of byte-sized items), allocate that space on the heap, then treat that as a raw pointer.
use std::mem;
#[allow(missing_copy_implementations)]
pub struct Gpio([u8; 4]);
impl Gpio {
fn new() -> Gpio { Gpio([0,0,0,0]) }
}
fn main() {
// Allocate some bytes and get a raw pointer
let a: *mut u8 = unsafe { mem::transmute(Box::new(Gpio::new())) };
// Use it here!
// When done... back to a box
let b: Box<Gpio> = unsafe { mem::transmute(a) };
// Now it will be dropped automatically (and free the allocated memory)
// Or you can be explicit
drop(b);
}
但是,我建议做这样的事情;这更明显,不需要堆分配:
However, I'd suggest doing something like this; it's a lot more obvious and doesn't need a heap allocation:
#[allow(missing_copy_implementations)]
pub struct Gpio([u8; 4]);
impl Gpio {
fn new() -> Gpio { Gpio([0,0,0,0]) }
fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
}
}
fn main() {
let mut g = Gpio::new();
let b = g.as_mut_ptr();
}
作为奖励,你有一个不错的地方来挂一些方法.as_mut_ptr
可能不需要是公共的,并且可以隐藏在 Gpio
结构上的公共方法后面.
As a bonus, you get a nice place to hang some methods on. Potentially as_mut_ptr
wouldn't need to be public, and could be hidden behind public methods on the Gpio
struct.
(也可以使用 uninitialized
而不是 [0,0,0,0]
)
// This depends on your library, check the FFI guide for details
extern {
fn gpio_init(gpio: *mut u8, pin: u8);
fn gpio_pin_on(gpio: *mut u8);
fn gpio_pin_off(gpio: *mut u8);
}
#[allow(missing_copy_implementations)]
pub struct Gpio([u8; 4]);
impl Gpio {
fn new(pin: u8) -> Gpio {
let mut g = Gpio([0,0,0,0]);
g.init(pin);
g
}
fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
}
fn init(&mut self, pin: u8) { unsafe { gpio_init(self.as_mut_ptr(), pin) } }
pub fn on(&mut self) { unsafe { gpio_pin_on(self.as_mut_ptr()) } }
pub fn off(&mut self) { unsafe { gpio_pin_off(self.as_mut_ptr()) } }
}
static BLUE_LED_PIN: u8 = 0x4;
fn main() {
let mut g = Gpio::new(BLUE_LED_PIN);
g.on();
g.off();
}
这篇关于为 C/FFI 库调用分配对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!