我很难绕过声明可变(或指针)变量并通过FFI与C代码交互.我大部分时间都在玩这个,并且由于Rust的发展速度很快,我发现了相互矛盾的例子.:)
情况是这样的:我有一个C函数,它接受一个指向a的指针struct,这个结构有ints和char *s的字段.我的理解是我需要在Rust中声明一个类似的结构来传递给extern C函数.
这是我在尝试解决这个问题时编写的示例文件:
main.rs
extern crate libc;
struct testStruct {
an_int: libc::c_int,
a_string: *mut libc::c_char
}
extern {
fn start_test(test: *mut testStruct) -> libc::c_int;
}
fn main() {
// println!("Hello, world!");
let test_struct = testStruct { an_int: 1, a_string: "hello" };
start_test(&mut test_struct);
}
Run Code Online (Sandbox Code Playgroud)
-
test_file.c
#include <stdio.h>
#include "test_file.h"
struct test_struct {
int an_int;
char *a_string;
};
int start_client(struct test_struct *test) {
printf("Test function!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
显然,实际的代码更复杂,我只是想尝试一个基本的例子来理解如何使用FFI在Rust中使用mutable/pointer.
在Rust中声明一个结构,或者只是一个变量的正确方法是什么,可以传递给期望指针的C代码?
结构的内存布局是未定义的(例如,允许编译器重新排序字段),除非您将该#[repr(C)]属性添加到结构中.该属性为struct提供了与C兼容的布局.
#[repr(C)]
struct TestStruct {
an_int: libc::c_int,
a_string: *mut libc::c_char
}
Run Code Online (Sandbox Code Playgroud)
在结构中使用原始指针工作正常,但我们可以做得更好.Rust中还有另外两个重要类型,它们只由一个指针组成:借用指针(&'a T或&'a mut T)和Box<T>.您可以改为使用这些类型,*const T或者*mut T明确表示指针借用现有值(并使编译器验证指针不会超过其指示对象)或指向堆上应该在指针时丢弃的对象(或包含它的结构)超出范围.但是,要小心Box<T>,因为在C代码仍有指向值的指针时,您可能会意外释放值.
#[repr(C)]
struct TestStruct<'a> {
an_int: libc::c_int,
a_string: &'a mut libc::c_char
}
Run Code Online (Sandbox Code Playgroud)
另外需要注意的是使用脂肪指针.在Rust中,一些指针类型很胖,即它们携带附加数据和指针.例如,切片(*const [T],*mut [T],&'a [T],&'a mut [T])可以被认为是含有一个指针的第一项和项的在切片(一个数的结构或元组usize); 性状对象(*const T,*mut T,&'a T,&'a mut T其中T是一个性状的名称)是由一个指针指向该对象和一个指向虚拟方法表中为性状实现.在定义与C结构匹配的Rust结构时,应避免使用这些类型.
您可以在Rust书的FFI部分找到有关使用Rust的FFI的更多信息.
| 归档时间: |
|
| 查看次数: |
285 次 |
| 最近记录: |