将C数组传递给Rust函数

将C数组传递给Rust函数,c,arrays,rust,C,Arrays,Rust,我正在尝试制作一个Rust动态库,并使用其他语言,如C、Python和其他语言。我已经成功调用了一个Rust函数,该函数使用Python中的i32参数。现在,我正在尝试创建一个函数,该函数接受一个数组(或指向它的指针,或将数据集传递给Rust所需的任何东西) #![板条箱类型=“dylib”] #[没有损坏] 酒吧外部“C”fn防锈倍数(尺寸:i32,阵列指针:&i32)->i32{ *(arrayPointer) } 这正如预期的那样有效。但是 #![板条箱类型=“dylib”] #[没有损

我正在尝试制作一个Rust动态库,并使用其他语言,如C、Python和其他语言。我已经成功调用了一个Rust函数,该函数使用Python中的i32参数。现在,我正在尝试创建一个函数,该函数接受一个数组(或指向它的指针,或将数据集传递给Rust所需的任何东西)

#![板条箱类型=“dylib”]
#[没有损坏]
酒吧外部“C”fn防锈倍数(尺寸:i32,阵列指针:&i32)->i32{
*(arrayPointer)
}
这正如预期的那样有效。但是

#![板条箱类型=“dylib”]
#[没有损坏]
酒吧外部“C”fn防锈倍数(尺寸:i32,阵列指针:&i32)->i32{
*(arrayPointer+1)//正在尝试获取下一个元素
}
失败于

error[E0614]:无法取消对'i32'类型的引用
-->src/lib.rs:4:5
|
4 |*(arrayPointer+1)//尝试获取下一个元素
|     ^^^^^^^^^^^^^^^^^^^
这样做:

pub extern fn rust_multiply(大小:i32,数组:&[i32])->i32

执行类似于
array[0]
的操作失败,出现“length=0”错误。

您必须努力提供纯C API,并使用不安全的代码实现一些转换。幸运的是,这并不难:

extern板条箱libc;
#[没有损坏]
酒吧外部“C”fn生锈(
大小:libc::size\u t,
数组指针:*常量libc::uint32\u t,
)->libc::uint32\u t{
内部锈蚀(不安全){
std::slice::from_raw_parts(数组指针为*const i32,大小为usize)
})作为libc::uint32\t
}
fn内部乘法(数组:&[i32])->i32{
断言!(!array.is_empty());
数组[0]
}
Rust FFI有一个很好的介绍。

获取无符号整数并将其转换为有符号整数。您可能需要的代码是

extern板条箱libc;
#[没有损坏]
酒吧外部“C”fn生锈(
大小:libc::size\u t,
数组指针:*常量libc::int32\u t,
)->libc::int32\t{
内部锈蚀(不安全){
std::slice::from_raw_parts(数组指针为*const i32,大小为usize)
})作为libc::int32\t
}
fn内部乘法(数组:&[i32])->i32{
断言!(!array.is_empty());
数组[0]
}

请注意,当使用不安全块时,由程序员验证其中的代码是否满足所有安全要求。在本例中,引用永远不能为
NULL
,因此您应该确实有一个断言,即
array\u pointer
不是
NULL
(除非您以某种方式保证它永远不会为NULL,这一点甚至更难)。@Shepmaster随territory(C FFI)而来。请注意,
&
指针也必须是非空的,因此如果它可以是空的,OP代码中的签名也是错误的。@delnan我可能误解了你的观点。我的观点是,
*const libc::uint32\t
允许为NULL,因为正如您所提到的,这是完全有效的C。此代码将其转换为一个切片,该切片不允许数据指针为NULL(不确定长度是否起作用-当长度为
0
时数据是否为NULL是否重要)。我只是说应该有一个
断言!(数组指针!=std::ptr::null())
在从原始零件调用
之前。“这一切都是为了尽我们所能保护我们自己不被疯狂的C电话骚扰。”谢普马斯特:当然,我同意。我想补充一点,(1)问题中已经存在空问题,(2)在与C交互时,Rust中永远无法排除某些危险。第二点是除此之外的一点,我必须事后承认。@delnan绝对是非常好的观点。我对地址(1)的OP发表了评论。遗憾的是,我们对此无能为力。外国金融机构消费者始终可以传入
(-1,0xDEADBEEF)
^_^您可能不想让
extern
函数接受
i32
或引用(例如
&i32
)。最好使用保证与您的平台匹配的C类型-
libc::uint32\u t
,如答案所示。此外,Rust引用保证为非空,但当您通过FFI对其进行校准时,并没有强制要求它为空。更安全的做法是接受
*const libc::uint32_t
(同样,如答案所示),然后在将其变为引用之前断言它为非NULL。