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

标签 rust 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) 一样传回 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 端的定义完全相同。如果您返回一个指针(此示例不是),则它是一个指针;如果您返回某个 id(此示例不是),则它是一个 id。

Rust 的 FFI 没有任何开销或抽象——你返回的就是返回的。

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);
}

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

关于rust - 当 Rust FFI 函数返回一个没有#[repr(C)] 的结构给 C 时返回什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54300524/

相关文章:

rust - 是否可以停用 cargo 中的文件锁定?

PHP FFI - 将数组 rom Rust 函数返回给 PHP

iterator - 如何获取引用的 IntoIterator 并返回对修改值的引用的盒装迭代器?

c - 从 Julia 更新 C 结构的字段值

rust - 如何调试卡在 `cargo build` 处的 "Updating crates.io index"?

json - 如何反序列化包含具有更多 JSON 的字符串的 JSON?

c++ - 从 C++ 生成 C 包装器?

java - 如何从 Java Web 应用程序调用 Prolog 谓词?

node.js - 如何在 Electron + Node -ffi-napi中获得正确的 native 内存地址

ruby - 如何使用 ruby​​ ffi 在 ruby​​ gem 中调用自定义 C 代码