使用数组参数从 C 调用 Rust 方法
Calling Rust method from C with array parameters
我正在尝试从我的 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]);
生锈:
#[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 中的 &[T]
与 C 中的 T []
或 T *
不同。你应该 从不 使用借用的指针与 Rust 的 C 代码交互。在与 C 代码交互时,您还应该 永远,永远 使用 [T]
或 str
。
曾经.
[T]
和 str
是 dynamically sized types,这意味着所有指向它们(任何类型)的指针都是常规指针大小的两倍。这意味着你的 C 代码传递了两个指针,而 Rust 期望 four。这是一个小小的奇迹,你的第二个例子没有在你的脸上爆炸。
Slice Arguments example from the Rust FFI Omnibus 几乎就是您想要的。
还有FFI chapter of the Rust Book.
编辑:那些C签名也是假的;首先,Rust 在任何地方接受的数组的大小都没有限制,所以我不确定 64
来自哪里。一个模糊可比较的 Rust 类型是 [u8; 64]
,但即使 that 也会 still 是不正确的,因为 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 book 中找到了很多关于此的有用信息,其中函数 "dot_product" 基本上完全符合我的要求:https://doc.rust-lang.org/nightly/book/no-stdlib.html
我正在尝试从我的 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]);
生锈:
#[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 中的 &[T]
与 C 中的 T []
或 T *
不同。你应该 从不 使用借用的指针与 Rust 的 C 代码交互。在与 C 代码交互时,您还应该 永远,永远 使用 [T]
或 str
。
曾经.
[T]
和 str
是 dynamically sized types,这意味着所有指向它们(任何类型)的指针都是常规指针大小的两倍。这意味着你的 C 代码传递了两个指针,而 Rust 期望 four。这是一个小小的奇迹,你的第二个例子没有在你的脸上爆炸。
Slice Arguments example from the Rust FFI Omnibus 几乎就是您想要的。
还有FFI chapter of the Rust Book.
编辑:那些C签名也是假的;首先,Rust 在任何地方接受的数组的大小都没有限制,所以我不确定 64
来自哪里。一个模糊可比较的 Rust 类型是 [u8; 64]
,但即使 that 也会 still 是不正确的,因为 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 book 中找到了很多关于此的有用信息,其中函数 "dot_product" 基本上完全符合我的要求:https://doc.rust-lang.org/nightly/book/no-stdlib.html