// ffi/rust-call-c/src/c_utils.cint sum(const int* my_array, int length) {int total = 0;for(int i = 0; i < length; i++) {total += my_array[i];}return total;}// ffi/rust-call-c/src/array.rsuse std::os::raw::c_int;// 对 C 库中的 sum 函数进行 Rust 绑定:extern "C" {fn sum(my_array: *const c_int, length: c_int) -> c_int;}fn main() {let numbers: [c_int; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];unsafe {let total = sum(numbers.as_ptr(), numbers.len() as c_int);println!("The total is {}", total);assert_eq!(total, numbers.iter().sum());}}
fn main() {初始化let mut v: Vec<u8> = vec![0; 80];初始化结构体let mut t = time::tm {tm_sec: 15,tm_min: 09,tm_hour: 18,tm_mday: 14,tm_mon: 04,tm_year: 120,tm_wday: 4,tm_yday: 135,tm_isdst: 0,};期望的日期格式let format = b"%Y-%m-%d %H:%M:%S\0".as_ptr();unsafe {调用time::strftime_in_rust(v.as_mut_ptr(), 80, format, &mut t);let s = match str::from_utf8(v.as_slice()) {=> r,=> panic!("Invalid UTF-8 sequence: {}", e),};: {}", s);}}
t 掌控(表述不完全准确,但基本上是这个意思。原因是抽象降级到C这一层的时候,就不再自动分辨所有权了)。生命期结束时,由Rust的RAII规则,自动销毁。rustffi 的cargo工程。// filename: cfoo.ctypedef struct Students {int num;int total;char name[20];float scores[3];} Student;Student* create_students(int n) {if (n <= 0) return NULL;Student *stu = NULL;stu = (Student*) malloc(sizeof(Student)*n);return stu;}void release_students(Student *stu) {if (stu != NULL)free(stu);}void print_students(Student *stu, int n) {int i;for (i=0; i<n; i++) {printf("C side print: %d %s %d %.2f %.2f %.2f\n",stu[i].num,stu[i].name,stu[i].total,stu[i].scores[0],stu[i].scores[1],stu[i].scores[2]);}}
gcc -fPIC -shared -o libcfoo.so cfoo.c
use std::os::raw::{c_int, c_float};use std::ffi::CString;use std::slice;#[repr(C)]#[derive(Debug)]pub struct Student {pub num: c_int,pub total: c_int,pub name: [u8; 20],pub scores: [c_float; 3],}#[link(name = "cfoo")]extern "C" {fn create_students(n: c_int) -> *mut Student;fn print_students(p_stu: *mut Student, n: c_int);fn release_students(p_stu: *mut Student);}fn main() {let n = 3;unsafe {let p_stu = create_students(n as c_int);assert!(!p_stu.is_null());let s: &mut [Student] = slice::from_raw_parts_mut(p_stu, n as usize);for elem in s.iter_mut() {elem.num = 1 as c_int;elem.total = 100 as c_int;let c_string = CString::new("Mike").expect("CString::new failed");let bytes = c_string.as_bytes_with_nul();elem.name[..bytes.len()].copy_from_slice(bytes);elem.scores = [30.0 as c_float, 40.0 as c_float, 30.0 as c_float];}println!("rust side print: {:?}", s);print_students(p_stu, n as c_int);release_students(p_stu);}println!("Over.");}
RUSTFLAGS='-L .' cargo build
.,其它类推。LD_LIBRARY_PATH="." target/debug/rustffi
rust side print: [Student { num: 1, total: 100, name: [77, 105, 107, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], scores: [30.0, 40.0, 30.0] }, Student { num: 1, total: 100, name: [77, 105, 107, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], scores: [30.0, 40.0, 30.0] }, Student { num: 1, total: 100, name: [77, 105, 107, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], scores: [30.0, 40.0, 30.0] }]C side print: 1 Mike 100 30.00 40.00 30.00C side print: 1 Mike 100 30.00 40.00 30.00C side print: 1 Mike 100 30.00 40.00 30.00Over.
typedef struct Students {int num;int total;char name[20];float scores[3];} Student;
#[repr(C)]#[derive(Debug)]pub struct Student {pub num: c_int,pub total: c_int,pub name: [u8; 20],pub scores: [c_float; 3],}
#[repr(C)]#[derive(Debug)]pub struct Student {pub num: c_int,pub total: c_int,pub name: *mut c_char,pub scores: [c_float; 3],}
fn create_students(n: c_int) -> *mut Student;
*mut Student 感觉只是指向一个实例的指针,或者说分不清是一个实例还是一个实例数组。slice::from_raw_parts() 和 slice::from_raw_parts_mut()。这个东西是神器。实现了我们这个场景下的核心要求,资源在C那边管理,Rust这边只是借用。但是填数据又是在Rust这边。\0 的。let c_string = CString::new("Mike").expect("CString::new failed");let bytes = c_string.as_bytes_with_nul();
这里这个as_bytes_with_nul()就是转成字节的时候,带上后面的 '\0'。
elem.name[..bytes.len()].copy_from_slice(bytes);
elem.name[0] = b'M';elem.name[1] = b'i';elem.name[2] = b'k';elem.name[3] = b'e';elem.name[4] = b'\0';
同时也可以看到,Rust和C竟然可以这样玩儿?Rust太强大了。除了C++,我暂时还想不到其它有什么语言能直接与C这样互操作的。
原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。