当 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 边界正确传输值的详细信息。免责声明:我是第一作者。