I\'m trying to call Rust code from my C project for an embedded device. The device prints over UART, so I am able to see what the result of my call is.
The following
A &[T]
in Rust is not the same thing as a T []
or a T *
in C. You should never use borrowed pointers for interacting with C code from Rust. You should also never, ever use [T]
or str
when interacting with C code.
Ever.
[T]
and str
are dynamically sized types, meaning that all pointers to them (of any kind) are twice the size of a regular pointer. This means that your C code is passing two pointers, whereas Rust is expecting four. It's a small miracle your second example didn't just explode in your face.
The Slice Arguments example from the Rust FFI Omnibus is very nearly exactly what you want.
There is also the FFI chapter of the Rust Book.
Edit: Those C signatures are also bogus; first of all, there is no limit on the size of the arrays Rust will accept anywhere, so I'm not sure where 64
came from. A vaguely comparable Rust type would be [u8; 64]
, but even that would still be incorrect, because C and Rust pass fixed-size arrays differently. C passes them by-reference, Rust passes them by-value.
Edit 2: assuming you're talking about the second func
, the Rust translation is just:
// 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]);
}
I also found a lot of useful information regarding this in the Rust nightly book, where the function "dot_product" basically does exactly what I was looking for: https://doc.rust-lang.org/nightly/book/no-stdlib.html