2016-05-25 18 views
2

は、私は、次の錆ライブラリがあるとします。CからVecを取ってRust関数を呼び出すことはできますか?

// lib.rs 
#![crate_type = staticlib] 

#[no_mangle] 
pub extern fn do_something(number: i32) { 
    // something 
} 

#[no_mangle] 
pub extern fn do_something_else(collection: &Vec<i32>) { 
    // something 
} 

私はCからdo_somethingを呼び出すために、ということを知って、私はちょうどint32_tを取っextern関数を宣言する必要があるだろうが、それはdo_something_elseを呼び出すことが可能ですか?もしそうなら、どうですか?

+1

私はCからの錆関数に整数配列ポインタを渡すことができると思います。操作のためにベクトルスライスを使用することができます。 – noshusan

+0

@noshusanあなたは 'pub extern fn do_thing(slice:&[i32])'のようなことをして、 'void do_thing(int32_t slice [])'のようにC側で宣言しますか? –

+0

私はよく分かりませんが、 'pub extern fn do_thing(slice:* [i32])'のように 'void do_thing(int32_t * slice [])'のようにc側で宣言することができます。ここでは、raw_pointerを使用しているため、安全でないブロックを宣言する必要があります。 – noshusan

答えて

4

あなたはです。ですが、より良い質問はですですか?

あなたがCからVecを構築することはできませんので、あなたが錆でそれを構築し、その後Vecへのポインタを所有しC. Cコードへのポインタを返す必要があるだろうとdo_something_elseを呼び出すときに、それをバック渡します。

次に、Rustメソッドをすべて反映する新しいFFIメソッドを作成する以外に、CのVecを実際に変更することはできないという問題があります。

錆の参照はNULLではないとを保証され、そしてCから呼び出されたときにそれは*const Vec<i32>を取る方が良いでしょうことを強制するものは何もありません、それは非NULLだと主張しているのでまたおそらくを取るべきではありませんそれを参照に変換します。

FFI境界でC配列を受け入れる可能性があります。 The Rust FFI Omnibus

use std::slice; 

pub extern fn do_something_else(p: *const i32, len: libc::size_t) { 
    let slice = unsafe { 
     assert!(!p.is_null()); 
     slice::from_raw_parts(p, len) 
    }; 
} 

必須リンク:あなたは両方を受け入れ、錆スライスを(あなたは、配列を所有していないであろうから)再構築したいので、Cアレイは、ポインタと長さです。


もしあなたが求めて何をするのに必要な本当に場合、それはおそらくこのようなものになります。

extern crate libc; 

#[no_mangle] 
pub extern fn make_vec() -> *mut Vec<i32> { 
    Box::into_raw(Box::new(Vec::new())) 
} 

#[no_mangle] 
pub extern fn add_number(vec: *mut Vec<i32>, val: libc::int32_t) { 
    let vec = unsafe { 
     assert!(!vec.is_null()); 
     &mut *vec 
    }; 

    vec.push(val);  
} 

#[no_mangle] 
pub extern fn print_vec(vec: *const Vec<i32>) { 
    let vec = unsafe { 
     assert!(!vec.is_null()); 
     &*vec 
    }; 

    println!("{:?}", vec);  
} 

#[no_mangle] 
pub extern fn drop_vec(vec: *mut Vec<i32>) { 
    unsafe { 
     assert!(!vec.is_null()); 
     Box::from_raw(vec); 
    } 
} 

そして(未テスト)のように使用されます:

// Add extern declarations 

int main(int argc, char *argv[]) { 
    void *v = make_vec(); // Use a real typedef here 
    add_number(v, 42); 
    print_vec(v); 
    drop_vec(v); 
} 

をあなたはvalgrindの下でこれを実行して、私が何か愚かなメモリをしていないことを確認したいと思うでしょう。

+0

私の意図は、C++プロジェクトからRustにいくつかのコードを移動することです - Rustでいくつかの計算を行い、結果を得てC++側で使用します。 C++プロジェクトを徐々にRustに移すというアイディアです。よりよいアプローチは何でしょうか? –

+0

@Romárioこれは難解な質問ですが、それ以上のことは知らずに、おそらくそれほど話題にはなりません。 Cコードをお持ちでしたら、このような変更を行う価値があると言えるでしょう。手作業で展開可能なベクターの実装を削除できるからです。しかし、C++は標準ライブラリにコレクションを持っているので、もう一方の標準ライブラリを切り替えるだけです。おそらく、あなたは1つ上のレベルを試して、 'std :: vector'を含む*オブジェクト*をRustに移動させることができますか? – Shepmaster

+0

'おそらく、あなたは1つ上のレベルを試して、std :: vectorを含むオブジェクトをRustに移動することができますか?FFI Omnibusにはこれに関するポインターがありますか? –

関連する問題