gpt4 book ai didi

c - 为 C/FFI 库调用分配对象

转载 作者:太空宇宙 更新时间:2023-11-04 02:00:16 25 4
gpt4 key购买 nike

我有一个 C 库,它有 gpio 实现。 gpio_type 是目标特定的,每个 MCU 对 gpio_type 都有不同的定义。库中的功能之一:

void gpio_init(gpio_type *object, int32_t pin);

我想使用 C 库函数在 Rust 中编写 Gpio 对象的抽象。因此需要类似不透明指针类型的东西(在 C++ 中,我只会创建一个类型为:gpio_type 的成员变量)。我想我会创建一个空枚举(或结构),为对象分配所需的空间并将其转换为匹配 C 层中的类型。

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 将处理的对象分配内存。

下面的代码片段根据反汇编生成指向地址 0 的指针。 Gpio新方法反汇编:

 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 吗?

最佳答案

looking for something to just allocate memory for the object which C will handle

像这样的事情呢?给结构一个实际大小(在这种情况下,通过给它一个固定大小的字节大小的项目数组),在堆上分配该空间,然后将其视为原始指针。

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);
}

但是,我建议这样做;它更明显,不需要堆分配:

#[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 结构的公共(public)方法后面。

(也可以使用 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 - 为 C/FFI 库调用分配对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28154683/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com