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

Ale*_*ons 3 c struct ffi rust

我将数据从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))
    }
}
Run Code Online (Sandbox Code Playgroud)

以下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;
}
Run Code Online (Sandbox Code Playgroud)

gdb的输出说:

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

字符串看起来很好,但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)
Run Code Online (Sandbox Code Playgroud)

使用:

cargo build
gcc --std=c11 -g -o main src/main.c /test/target/debug/libtest.so -L target/debug/
Run Code Online (Sandbox Code Playgroud)

She*_*ter 6

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

如关于对象的Rust FFI Omnibus章节所示,您应该使用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))
}
Run Code Online (Sandbox Code Playgroud)

您的C函数应标记为返回指针:

extern const my_struct *get_my_struct(void);

// ...

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

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


如果您想直接返回结构,请更改Rust代码以不执行分配:

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

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