c - 为什么将堆分配的结构从 Rust 传递到 C 时,我的整数值发生了变化?

标签 c struct rust ffi

我正在将数据从 Rust 传递到 C。虽然传递原语似乎很容易,但我有点迷失了结构。

我有以下 Rust 代码:

use ::std::os::raw::*;

static NAME: &[c_char] = &[65, 66, 67, 0];

#[repr(C)]
pub struct MyStruct {
    pub x: c_int,
    pub y: *const c_char,
}

#[no_mangle]
pub extern "C" fn get_my_struct() -> *const MyStruct {
    let my_struct = MyStruct {
        x: 11 as c_int,
        y: NAME.as_ptr(),
    };

    unsafe {
        ::std::mem::transmute(Box::new(my_struct))
    }
}

以及以下 C 代码:

typedef struct _my_struct my_struct;
extern const my_struct get_my_struct(void);

struct _my_struct {
    int x;
    const char *y;
};

int main(void) {
  my_struct my_complex_struct = get_my_struct();

  return 0;
}

gdb 的输出显示:

(gdb) p my_complex_struct
$1 = {x = 6295568, y = 0x7ffff7bce1e0 <ref> "ABC"}

字符串看起来不错,但 int 肯定是关闭的。我在这里错过了什么?为什么 x 的值是 6295568 而不是 11?

编译:

gcc (Debian 4.9.2-10) 4.9.2
rustc 1.20.0-nightly (8d22af87d 2017-07-22)
cargo 0.21.0-nightly (ffab51954 2017-07-18)

使用:

cargo build
gcc --std=c11 -g -o main src/main.c /test/target/debug/libtest.so -L target/debug/

最佳答案

您遇到问题是因为您的 ABI 不匹配。您正在返回一个指向已分配结构的指针,但您的 C 代码声称该函数直接返回一个结构。

The Rust FFI Omnibus chapter on objects 中所示, 你应该使用 Box::into_raw :

#[no_mangle]
pub extern "C" fn get_my_struct() -> *const MyStruct {
    let my_struct = MyStruct {
        x: 11 as c_int,
        y: NAME.as_ptr(),
    };

    Box::into_raw(Box::new(my_struct))
}

你的 C 函数应该被标记为返回一个指针:

extern const my_struct *get_my_struct(void);

// ...

int main(void) {
  const my_struct *my_complex_struct = get_my_struct();
  // ...
}
(lldb) p *my_complex_struct
(my_struct) $1 = (x = 11, y = "ABC")

代码也有内存泄漏;您需要将指针返回给 Rust,以便它可以被正确地释放。


如果您打算直接返回结构,请将您的 Rust 代码更改为不执行分配:

#[no_mangle]
pub extern "C" fn get_my_struct() -> MyStruct {
    MyStruct {
        x: 11 as c_int,
        y: NAME.as_ptr(),
    }
}
(lldb) p my_complex_struct
(my_struct) $0 = (x = 11, y = "ABC")

免责声明:我是Omnibus 的主要作者。

关于c - 为什么将堆分配的结构从 Rust 传递到 C 时,我的整数值发生了变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45360245/

相关文章:

rust - 将值格式化为多种字符串的惯用 Rust 方法是什么?

c - 父进程和 2 个子进程之间通过 c 中的半双工管道进行通信的问题

c - C中AVR的舍入数字

c - 分配给结构中的静态数组时堆缓冲区溢出

iphone - 尽管标记了文件 -fno-objc-arc,但 ARC 禁止在结构或联合中使用 Objective-C 对象

json - 在同一属性中解析具有多种表示形式的 JSON

c - 在 C 中初始化定时器

c++ - 使用 scanf() 获取数组中的字符(不以空格分隔)

将结构转换为数组?

multithreading - Rust:允许多个线程修改图像(向量的包装)?