Allocating an object for C / FFI library calls

前端 未结 1 753
隐瞒了意图╮
隐瞒了意图╮ 2021-01-16 15:09

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

相关标签:
1条回答
  • 2021-01-16 15:21

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

    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 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.

    (might also be able to use uninitialized instead of [0,0,0,0])

    An expanded example of the second suggestion

    // 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();
    }
    
    0 讨论(0)
提交回复
热议问题