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

我正在尝试从我的C项目中为嵌入式设备调用Rust代码。 设备在UART上打印,因此我可以看到通话结果是什么。

下面的C和Rust代码按预期工作(我省略了许多使编译时需要的样板代码)。

C:

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

锈:

 #[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]); 

锈:

 #[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。

Rust中的A &[T]与C中的T []T * 。您不应该使用借来的指针与Rust的C代码进行交互。 你也不应该在与C代码交互时使用[T]str

曾经

[T]str是动态大小的类型 ,这意味着它们(任何类型)的所有指针都是常规指针的两倍。 这意味着你的C代码传递两个指针,而Rust则期望四个 。 这是一个小小的奇迹,你的第二个例子不只是在你脸上爆炸。

Rust FFI Omnibus的Slice Arguments示例几乎完全符合您的要求。

还有Rust Book的FFI章节 。

编辑 :那些C签名也是假的; 首先,Rust在任何地方都可以接受的数组大小没有限制,所以我不确定64来自哪里。 一个模糊的Rust类型将是[u8; 64] [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]); } 

我还在Rust nightly书中找到了很多有用的信息,其中函数“dot_product”基本上完全符合我的要求: https ://doc.rust-lang.org/nightly/book/no-stdlib html的