使用数组参数从 C 调用 Rust 方法

标签 c rust ffi

我正在尝试从我的 C 项目中为嵌入式设备调用 Rust 代码。该设备通过 UART 进行打印,因此我能够看到调用的结果。

以下 C 和 Rust 代码按预期工作(我省略了很多使其编译所需的样板 Rust 代码)。

C:

uint8_t input[] = {1,2,3};
uint8_t output[] = {4,5,6};
output = func(input, output);
printf("Sum: %d", output[0]);

使用rust :

#[no_mangle]
pub extern fn func(input: &[u8], dst: &mut[u8]) -> u8 {
  3
}

这会按预期打印 3。但我坚持改变作为引用传入的数组:

C:

uint8_t input[] = {1,2,3};
uint8_t output[] = {4,5,6};
func(input, output);
printf("Sum: %d", output[0]);

使用rust :

#[no_mangle]
pub extern fn func(input: &[u8], dst: &mut[u8]) {
  for i in (0..1) {
      dst[i] = input[i];
  }
}

这会编译,但会打印 4 而不是预期的 1。出于某种原因,我无法更改数组的值。有什么想法吗?

编辑:C函数声明分别是:

extern uint8_t func(uint8_t in[64], uint8_t output[64]);
extern void func(uint8_t in[64], uint8_t output[64]);

EDIT2:更新代码: C:

uint8_t input[64];
uint8_t output[64];
for(uint8_t = 0; i < 64; i++) {
    input[i] = i;
}
func(input, output);
printf("Sum: %d", output[2]);

期望输出 2。

最佳答案

A &[T] 在 Rust 中T []T * 不同C 中的。您应该永远使用借用的指针与来自 Rust 的 C 代码进行交互。在与 C 代码交互时,您还应该永远、永远使用[T]str

曾经

[T]strdynamically sized types ,这意味着所有指向它们(任何类型)的指针都是常规指针大小的两倍。这意味着您的 C 代码正在传递两个指针,而 Rust 期望四个。你的第二个例子没有在你的脸上爆炸,这真是一个小奇迹。

Slice Arguments example from the Rust FFI Omnibus几乎正是您想要的。

还有 FFI chapter of the Rust Book .

编辑:那些C签名也是假的;首先,Rust 在任何地方接受的数组大小都没有限制,所以我不确定 64 来自哪里。一个模糊可比的 Rust 类型是 [u8; 64],但即使那个仍然是不正确的,因为 C 和 Rust 以不同的方式传递固定大小的数组。C 传递它们通过引用,Rust 按值传递它们。

编辑 2:假设您正在谈论第二个 func,Rust 翻译就是:

// C ffi signature:
// void copy(uint8_t src[4], uint8_t dst[4]);
#[no_mangle]
pub unsafe extern fn copy(src: *const [u8; 4], dst: *mut [u8; 4]) {
    if src.is_null() { return; }
    if dst.is_null() { return; }

    // Convert to borrowed pointers.
    let src: &[u8; 4] = &*src;
    let dst: &mut [u8; 4] = &mut *dst;

    for (s, d) in src.iter().zip(dst.iter_mut()) {
        *d = *s;
    }
}

#[cfg(test)]
#[test]
fn test_copy() {
    let a = [0, 1, 2, 3];
    let mut b = [0; 4];
    unsafe { copy(&a, &mut b); }
    assert_eq!(b, [0, 1, 2, 3]);
}

关于使用数组参数从 C 调用 Rust 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40546150/

相关文章:

rust - 仅为特定字段派生属性,就像 serde 一样

rust - 如何从迭代器循环内部跳过 n 个项目?

rust - 如何从 Rust 访问用 C 声明的函数指针的零终止数组?

c - Arduino 端口重定位(PORTD 到 PORTB)

c - 这段代码打印了什么以及为什么?

c - 按特定字符拆分单词适用于字符串,但不适用于 argv[1]

c++ - 什么是 FFI 扩展?

c - 程序在读取第一个scanf(int类型)后进入 "while"时崩溃

mysql - 如何将 Homebrew 安装的 mysql-client 与 diesel-cli 链接起来?

haskell - Haskell 中的 FFI,关于 LANGUAGE CPP 的问题以及如何在 FFI 中使用 c 结构