2016-09-16 20 views
2

C++からRustで書かれたいくつかの関数を呼び出そうとしています。これまでのところ、私はかなり成功しましたが、ランタイム中にはまだCString関連のパニックで少し問題があります。C++とRust-CStringパニックのインターフェイス

関数helloは、入力文字列を他の文字列と連結して返します。ここで

は私のfun.rsです:

use std::ffi::CString; 

#[no_mangle] 
pub extern "C" fn add(a: i32, b: i32) -> i32 { 
    a + b 
} 

#[no_mangle] 
pub extern "C" fn hello(cs: CString) -> CString { 
    let slice = cs.to_str().unwrap(); 
    let mut s = "Hello, ".to_string(); 
    s = s + slice; 

    CString::new(&s[..]).unwrap() // runtime error 
    // CString::new(cs).unwrap() // empty string if no borrow 
    // cs       // works if no borrow, but this is not what I meant 
} 

ここmain.cppです:

#include <iostream> 
using namespace std; 

extern "C" { 
    int add(int a, int b); 
    const char* hello(const char*x); 
} 

int main() 
{ 
    int a, b; 
    cin >> a >> b; 
    cout << add(a,b) << ";" << hello("Pawel") << std::endl; 
    return 0; 
} 

そしてmakefile

rust: 
     rustc --crate-type=staticlib -C panic=abort fun.rs 

cpp: 
     g++ -c main.cpp 

link: 
     g++ main.o -L . libfun.a -o main -lpthread -ldl -lgcc_s -lc -lm -lrt -lutil 

コマンド実行ファイルを実行するには:

を10
$ make rust 
$ make cpp 
$ make link 
$ ./main 
1 2 

実行出力:

1 2 
thread '<unnamed>' panicked at 'index 18446744073709551615 out of range for slice of length 0', ../src/libcore/slice.rs:549 
note: Run with `RUST_BACKTRACE=1` for a backtrace.. 

バックトレース:

stack backtrace: 
    1:   0x435d4f - std::sys::backtrace::tracing::imp::write::h46e546df6e4e4fe6 
    2:   0x44405b - std::panicking::default_hook::_$u7b$$u7b$closure$u7d$$u7d$::h077deeda8b799591 
    3:   0x443c8f - std::panicking::default_hook::heb8b6fd640571a4f 
    4:   0x4099fe - std::panicking::rust_panic_with_hook::hd7b83626099d3416 
    5:   0x4442a1 - std::panicking::begin_panic::h941ea76fc945d925 
    6:   0x40b74a - std::panicking::begin_panic_fmt::h30280d4dd3f149f5 
    7:   0x44423e - rust_begin_unwind 
    8:   0x451d8f - core::panicking::panic_fmt::h2d3cc8234dde51b4 
    9:   0x452073 - core::slice::slice_index_len_fail::ha4faf37254d75f20 
    10:   0x40e903 - std::ffi::c_str::CStr::to_str::ha9642252376bab15 
    11:   0x4048e0 - hello 
    12:   0x40476f - main 
    13:  0x7f78ff688f44 - __libc_start_main 
    14:   0x404678 - <unknown> 
    15:    0x0 - <unknown> 

任意のアイデアなぜ錆が慌てていますか?

+0

FFI境界に 'CString'を渡すのが安全だと思うのはなぜですか? – Shepmaster

+2

http://jakegoulding.com/rust-ffi-omnibus/string_arguments/とhttp://jakegoulding.com/rust-ffi-omnibus/string_return/ – Shepmaster

+0

@Shepmasterまあ、私の推論は、もし私が 'int32'を渡すことができるということです。前後に+ 'CString'が簡単に出入りできる(コメント付きコード)場合は、何らかの方法で動作するはずです。 URLが答えである@Shepmaster – Scony

答えて

5

ルストのCStringは、Cのconst char *と互換性がありません。ここでは、標準ライブラリからCStringの定義があります:

pub struct CString { 
    inner: Box<[u8]>, 
} 

このBox<[u8]>タイプはファットポインタ、スライスの項目へのポインタとusizeとしてスライスの長さを含む、すなわちタプルです。

代わりに行うべきことは、Rust関数を*const c_char引数にしてから、CStr::from_ptrをそのポインタを引数として呼び出してCStrの値を取得することです。

戻り値に関しては、少し問題があります。関数が新しい文字列を割り当てた後、ポインタを返します。繰り返しますが、*const c_charを返す必要があります。連結するCStringの値にCString::into_rawを呼び出すことで対応できます。しかしメモリリークを避けるには、helloによって返されたポインタを取り戻し、CString::from_rawを呼び出してCStringを再作成するRust関数も提供する必要があります。 CStringのデストラクタが実行され、メモリが解放されます。

関連する問題