2016-05-25 48 views
2

假設我有以下鏽庫:是否可以調用一個Rust函數從C中獲取一個Vec?

// 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,我只是需要聲明一個extern函數獲取int32_t,但有可能調用do_something_else?如果是這樣,怎麼樣?

+1

我認爲你可以將整數數組指針傳遞給C中的生鏽函數,然後你可以使用矢量切片來完成操作。 – noshusan

+0

@noshusan你的意思是做一些像'pub extern fn do_thing(slice:&[i32])'然後在C方聲明它像'void do_thing(int32_t slice [])''? –

+0

我不確定,但是你可以做一些像'pub extern fn do_thing(slice:* [i32])'這樣的聲明在c面,像'void do_thing(int32_t * slice [])'一樣。這裏你使用的是raw_pointer,所以你必須聲明一個不安全的塊。 – noshusan

回答

4

可以,但最好的問題是應該你?

既然你不能在C構建一個Vec,你必須建立它在鏽,然後返回一個指向下的C代碼將自己的指針Vec,然後將其傳回調用do_something_else時。

然後存在的問題是,您無法真正修改C中的Vec,除了創建新的FFI方法來鏡像所有Rust方法。

你也可能不應該採取,因爲鏽病引用保證不爲NULL,並沒有什麼強制執行,從C.調用時最好是採取*const Vec<i32>,斷言它的非NULL和將其轉換爲參考。

很可能您希望通過FFI邊界接受C數組。 C數組的指針和長度,所以你會同時接受並重組防鏽(因爲你沒有自己的數組):

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

強制性鏈接The Rust FFI Omnibus


如果你真的需要做的,你問什麼的話,大概是這個樣子:

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這是一個難以回答的問題,不知道更多,可能會成爲SO的焦點。如果你有C代碼,我可能會說這是值得做這種改變的,因爲那樣你可以刪除你手工製作的可擴展矢量實現。但是,C++在標準庫中有集合,所以你只需要爲另一個切換一個標準庫。也許你可以嘗試更高一級,並將包含'std :: vector'的* object *移動到Rust? – Shepmaster

+0

'也許你可以嘗試更高一級並將包含std :: vector的對象移動到Rust?'FFI Omnibus是否有任何指針? –

相關問題