如何为使用&mut [u8]和u32的C回调指定调用约定?

时间:2019-04-15 19:22:26

标签: rust ffi calling-convention

我有一个板条箱,其中存放一个函数指针(用C定义),并调用一些预定义的参数。我怀疑我无法获得符合C调用约定的调用。我已经审查了the relevant Rust docs,并认为我在适当的地方指定了调用约定...

一个简单的例子来说明:

带有简单结构的Rust板条箱,其中包含缓冲区和用于包装它的函数指针:

pub type Callback = extern "C" fn(buffer: &mut [u8], current_index: u32, max_index: u32) -> u32;
const BUFFER_SIZE: usize = 32_767;
pub type DataBuffer = [u8; BUFFER_SIZE];

#[no_mangle]
pub struct Foo {
    buffer: DataBuffer,
    pub current_index: u32,
    callback: Option<Callback>,
}

impl Foo {
    fn new() -> Self {
        Foo {
            current_index: 0,
            buffer: [0u8; BUFFER_SIZE],
            callback: None,
        }
    }
    fn add_callback(&mut self, callback: Callback) {
        self.callback = Some(callback);
    }

    fn call_callback(&mut self) {
        let increment = self.callback.expect("")(
            self.buffer
                .get_mut(self.current_index as usize..)
                .expect(""),
            self.current_index,
            BUFFER_SIZE as u32,
        );
        self.current_index += increment;
    }
}
#[no_mangle]
pub extern "C" fn FooNew() -> Box<Foo> {
    Box::new(Foo::new())
}
#[no_mangle]
pub extern "C" fn FooAddCallback(foo: &mut Foo, callback: Callback) {
    foo.add_callback(callback);
}
#[no_mangle]
pub extern "C" fn FooCallCallback(foo: &mut Foo) {
    foo.call_callback();
}
#[no_mangle]
pub extern "C" fn FooPrint(foo: &mut Foo) {
    for c in foo.buffer.iter() {
        print!("{}", *c as char);
    }
    println!("\n");
}

和一些相应的C代码来调用它:

#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Foo Foo;

extern Foo* FooNew();
extern void FooAddCallback(Foo* foo, void* callback);
extern void FooCallCallback(Foo* foo);
extern void FooPrint(Foo* foo);

unsigned int getHeaders(char* buffer, unsigned int current_index, unsigned int max_index)
{
    if (current_index > max_index)
    {
        printf("\nError current_index(%d) > max_index(%d) !!\nThis is most likely a C-api byte order problem\n", current_index, max_index);
        exit(-1);
    }
    strcpy(buffer, "~HEADER~\0");

    return 9;
}

int main()
{
    Foo* foo = FooNew();
    FooAddCallback(foo, getHeaders);
    FooCallCallback(foo);
    FooCallCallback(foo);
    FooCallCallback(foo);

    FooPrint(foo);

    return 0;
}

运行时,回调的后两个参数传递不正确(即current_index的参数传递给max_index,反之亦然,在上面的示例中,其0传递给{{1 }}和32767到max_index)。反转这些args的顺序(看似使调用顺序读取不正确)会导致其正确执行...

我怀疑我只是在错误地调用回调,或者需要以其他方式指定调用约定。

是的,提到了this question。这是他们问题的直接反面,但是精神是相同的。 阵列/切片无法直接通过FFI 传递。

0 个答案:

没有答案