简体   繁体   English

当Rust FFI函数将没有#[repr(C)]的结构返回给C时,返回什么?

[英]What is returned when a Rust FFI function returns a struct without #[repr(C)] to C?

EDIT: It was pointed out that my example isn't complete enough to be useful. 编辑:有人指出,我的示例还不够完整,无法使用。 My question is resolved, but if you're interested in looking at the complete code you can see it here . 我的问题已经解决,但是如果您有兴趣查看完整的代码,可以在这里查看

Given the following code: 给出以下代码:

#[no_mangle]
pub extern "C" fn create_acceptor() -> Acceptor {
    Acceptor {}
}

pub struct Acceptor {}

If I call this from C what does it actually get? 如果我从C调用它,它实际上会得到什么? Is it a pointer? 是指针吗? An id of some sort? 某种ID?

I'm currently using code like the following on the C side: 我目前在C端使用如下代码:

extern int create_acceptor();

int main(int argc, char **argv) {
        int acceptor = create_acceptor();
        return 0;
}

It seems to work fine. 似乎工作正常。 I'm using it like an opaque type that I pass back to Rust like acceptor_doSomething(acceptor) . 我像不透明类型一样使用它,我像acceptor_doSomething(acceptor)一样传递回Rust。

But I'm confused because it doesn't seem to matter what type I use for acceptor on the C side. 但是我很困惑,因为在C端使用哪种类型的acceptor器似乎并不重要。 void* and int both behave the same. void*int行为相同。 Also, the documentation seems to indicate that I should be using #[repr(C)] , but it seems to work without it. 另外,文档似乎表明我应该使用#[repr(C)] ,但如果没有它,它似乎可以工作。 Why is that? 这是为什么?

When printing the value received on the C side, it's showing very small integers, so I'm guessing it's an id on the Rust side? 当打印在C端接收到的值时,它显示的是非常小的整数,所以我猜它在Rust端是一个id?

TL;DR: The example isn't a useful one and doesn't show anything. TL; DR:该示例不是有用的示例,没有显示任何内容。

what does it actually get? 它实际上得到了什么? Is it a pointer? 是指针吗? An id of some sort? 某种ID?

It's the struct, exactly as defined on the Rust side. 这是结构,完全与Rust端定义的一样。 It's a pointer if you return a pointer (this example does not) or an id if you return some id (this example does not). 如果您返回一个指针(此示例未返回),则为一个指针;如果您返回某个ID(此示例未返回),则为一个id。

Rust's FFI imposes no overhead or abstraction — what you return is what is returned. Rust的FFI不会增加开销或抽象-您返回的就是返回的东西。

the documentation seems to indicate that I should be using #[repr(C)] 该文档似乎表明我应该使用#[repr(C)]

Yes, you should . 是的, 你应该 Without it, your code is most likely undefined behavior. 没有它,您的代码很可能是未定义的行为。 The layout of a Rust struct is not yet guaranteed. 尚未保证Rust结构的布局。 Without specifying the representation as C, there's no way for the C code to know which fields are where. 如果不将表示形式指定为C,则C代码无法知道哪些字段位于何处。

but it seems to work without it 但是似乎没有它就可以工作

That's because your example struct has no fields and thus no size (which AFAIK isn't even valid in C without non-standard extensions). 那是因为您的示例结构没有字段,因此没有大小(如果没有非标准扩展名,则AFAIK在C语言中甚至无效)。 Rust basically never even needs to look at the data (what data?) so it doesn't matter what you pass back. Rust基本上甚至不需要查看数据(什么数据?),所以回传什么都没有关系。

When printing the value received on the C side, it's showing very small integers 打印在C端接收到的值时,它显示非常小的整数

This is probably just junk on the stack laying around. 这可能只是周围堆积的垃圾。 Literally uninitialized data. 字面上未初始化的数据。

Using a struct with fields without #[repr(C)] 将结构体与没有#[repr(C)]字段一起使用

This is bad . 不好 Don't do it. 不要这样 String is a struct with non-trivial fields and it is not marked #[repr(C)] . String是具有非平凡字段的结构,并且未标记为#[repr(C)]

Cargo.toml Cargo.toml

[package]
name = "shear"
version = "0.1.0"
authors = ["An Devloper"]

[lib]
crate-type = ["cdylib"]

[dependencies]

src/lib.rs 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 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);
}

Execution 执行

$ 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

Please read the The Rust FFI Omnibus for details about how to properly transfer values across the FFI boundary. 请阅读Rust FFI Omnibus,以获取有关如何在FFI边界上正确传输值的详细信息。 Disclaimer: I am the primary author. 免责声明:我是第一作者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM