2016-05-25 24 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是否有任何指针? –

相关问题