当 Rust FFI 函数 returns 没有 #[repr(C)] 的结构到 C 时返回什么?
What is returned when a Rust FFI function returns a struct without #[repr(C)] to C?
编辑:有人指出我的示例不够完整,无法发挥作用。我的问题已经解决了,但是如果你有兴趣看完整的代码你可以看看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?
TL;DR:该示例不是一个有用的示例,也没有显示任何内容。
what does it actually get? Is it a pointer? An id of some sort?
它是结构,与 Rust 端定义的完全一样。如果你 return 一个指针(这个例子没有)或者一个 id 如果你 return 一些 id(这个例子没有),它是一个指针。
Rust 的 FFI 没有任何开销或抽象 — 你 return 就是 returned 的。
the documentation seems to indicate that I should be using #[repr(C)]
是的,你应该。没有它,您的代码很可能是未定义的行为。 Rust 结构的布局尚未得到保证。如果不将表示指定为 C,C 代码就无法知道哪些字段在哪里。
but it seems to work without it
那是因为您的示例结构没有字段,因此没有大小(如果没有非标准扩展,AFAIK 在 C 中甚至无效)。 Rust 基本上从不需要查看数据(什么数据?)所以你传回什么并不重要。
When printing the value received on the C side, it's showing very small integers
这可能只是堆栈中的垃圾。字面上未初始化的数据。
使用不带 #[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 边界正确传输值的详细信息。免责声明:我是第一作者。
编辑:有人指出我的示例不够完整,无法发挥作用。我的问题已经解决了,但是如果你有兴趣看完整的代码你可以看看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)
.
但我很困惑,因为在 C 端 acceptor
使用什么类型似乎并不重要。 void*
和 int
的行为相同。此外,文档似乎表明我应该使用 #[repr(C)]
,但没有它似乎也能正常工作。这是为什么?
当打印 C 端收到的值时,它显示的是非常小的整数,所以我猜它是 Rust 端的一个 id?
TL;DR:该示例不是一个有用的示例,也没有显示任何内容。
what does it actually get? Is it a pointer? An id of some sort?
它是结构,与 Rust 端定义的完全一样。如果你 return 一个指针(这个例子没有)或者一个 id 如果你 return 一些 id(这个例子没有),它是一个指针。
Rust 的 FFI 没有任何开销或抽象 — 你 return 就是 returned 的。
the documentation seems to indicate that I should be using
#[repr(C)]
是的,你应该。没有它,您的代码很可能是未定义的行为。 Rust 结构的布局尚未得到保证。如果不将表示指定为 C,C 代码就无法知道哪些字段在哪里。
but it seems to work without it
那是因为您的示例结构没有字段,因此没有大小(如果没有非标准扩展,AFAIK 在 C 中甚至无效)。 Rust 基本上从不需要查看数据(什么数据?)所以你传回什么并不重要。
When printing the value received on the C side, it's showing very small integers
这可能只是堆栈中的垃圾。字面上未初始化的数据。
使用不带 #[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 边界正确传输值的详细信息。免责声明:我是第一作者。