编辑:有人指出,我的示例不够完整,无法使用。我的问题已经解决,但是如果您有兴趣查看完整的代码,可以here看到它。
给出以下代码:
#[no_mangle]
pub extern "C" fn create_acceptor() -> Acceptor {
Acceptor {}
}
pub struct Acceptor {}
如果我从C调用它,它实际上会得到什么?是指针吗?某种ID?
我目前在C端使用如下代码:
extern int create_acceptor();
int main(int argc, char **argv) {
int acceptor = create_acceptor();
return 0;
}
似乎工作正常。我像不透明类型一样使用它,像acceptor_doSomething(acceptor)
这样传递回Rust。
但是我很困惑,因为在C端对acceptor
使用哪种类型似乎无关紧要。 void*
和int
的行为相同。另外,文档似乎表明我应该使用#[repr(C)]
,但似乎没有它就可以工作。为什么会这样?
在打印C端接收到的值时,它显示的是非常小的整数,所以我猜它是Rust端的id?
答案 0 :(得分:3)
TL; DR:该示例不是有用的示例,并且不显示任何内容。
实际上得到了什么?是指针吗?某种ID?
这是结构,完全符合Rust方面的定义。如果您返回一个指针(此示例未返回),则为一个指针;如果您返回某个ID(此示例未返回),则为一个id。
Rust的FFI不会增加开销或抽象-您返回的是返回的内容。
文档似乎表明我应该使用
#[repr(C)]
是的,您应该。没有它,您的代码很可能是未定义的行为。尚未保证Rust结构的布局。如果不将表示形式指定为C,则C代码无法知道哪些字段位于何处。
但似乎没有它就可以工作
那是因为您的示例结构没有字段,因此没有大小(如果没有非标准扩展名,则AFAIK在C语言中甚至无效)。 Rust基本上甚至不需要查看数据(什么数据?),所以回传什么都没有关系。
打印在C端接收到的值时,它显示出非常小的整数
这可能只是周围堆积的垃圾。字面上未初始化的数据。
#[repr(C)]
的字段的结构这是不好。不要这样String
是具有非平凡字段的结构,并且未标记为#[repr(C)]
。
Cargo.toml
[package]
name = "shear"
version = "0.1.0"
authors = ["An Devloper"]
[lib]
crate-type = ["cdylib"]
[dependencies]
src / lib.rs
// Don't do this, `String` isn't #[repr(C)]!
#[no_mangle]
pub extern "C" fn create_example() -> String {
String::from("hello")
}
// Don't do this, `String` isn't #[repr(C)]!
#[no_mangle]
pub extern "C" fn use_example(e: String) {
println!("{}", e);
}
main.c
extern int create_example();
extern void use_example(int example);
int main(int argc, char **argv) {
int example = create_example();
use_example(example);
}
执行
$ cargo build
Compiling shear v0.1.0 (file:///home/ubuntu/shear)
Finished dev [unoptimized + debuginfo] target(s) in 1.02s
$ gcc -o example main.c -L target/debug/ -lshear
$ LD_LIBRARY_PATH=target/debug/ ./example
Segmentation fault
请阅读The Rust FFI Omnibus,以获取有关如何在FFI边界上正确传输值的详细信息。免责声明:我是主要作者。