Rust与C交互(FFI)中复杂类型的处理

0前言

简单类型,libc都有对应的不再赘述(没有对应的bool类型),主要是 针对 struct 和 struct 数组的交互

1内容

C类型Rust类型说明
struct_name **mut struct_namestruct指针的转换
结构体中的数组slice见具体例子

struct指针 *有两层意思:
1. 指向一个struct对象

2Rust调用C

2.1指向一个struct对象

C语言如下

struct FIParam
{
    int n_min_face_size;
    int n_roll_angle;
    int b_only_detect;
    unsigned long long reserved;
};

#define LIBDLL extern "C" _declspec(dllexport) 
//函数
LIBDLL int      fi_create(short nChannelNum, FIParam* pParam);

Rust对应如下

extern crate libc;
use libc::{c_int,c_ulonglong,c_long,c_float,c_uchar,c_short};

#[repr(C)]
pub struct FIParam
{
    pub n_min_face_size:c_int ,
    pub n_roll_angle:c_int,
    pub b_only_detect:c_int ,
    pub reserved:c_ulonglong,
}
//函数
 #[link(name = "库文件名(无后缀)")]
 extern {
      pub fn fi_create(n_channel_num:c_short,p_param: *mut FIParam) ->c_int ;
 }
调用
let mut  param=Box::new(FIParam
{
    n_min_face_size:80 ,
    n_roll_angle:30,
    b_only_detect:1 ,
    reserved:0,
 });


let result: i32 = unsafe {
    ffi::fi_create(10 as c_short, &mut *param) as i32
};

2.2指向一个struct数组

C语言如下


struct FIPoint
 {
     long x;
     long y;
 };

struct FIFacePos
{
    FIPoint     pt_left_eye;
    FIPoint     pt_right_eye;
    FIPoint     pt_mouth;
    FIPoint     pt_nose;            
    FIFaceAngle f_angle;
    int         n_quality;
    unsigned char p_facial_data[512];//值得注意
};

#define LIBDLL extern "C" _declspec(dllexport) 
//函数pfps指向的是数组
LIBDLL int      fi_detect_face(short nChannelID, int bpp, int nWidth, int nHeight, FIFacePos* pfps, int nMaxFaceNums, int nSampleSize = 640);

Rust对应

extern crate libc;
use libc::{c_int,c_ulonglong,c_long,c_float,c_uchar,c_short};
use std::mem;
#[repr(C)]
pub struct FIPoint
{
    pub x:c_long,
    pub y:c_long,
}
impl FIPoint{
    pub fn new() -> FIPoint {
       FIPoint{
          x: 0 as c_long,
          y: 0 as c_long,
      }
   }
}

#[repr(C)]
pub struct FIFacePos
{
   pub pt_left_eye:FIPoint,
   pub pt_right_eye:FIPoint,
   pub pt_mouth:FIPoint,
   pub pt_nose:FIPoint,                             
   pub f_angle:FIFaceAngle,
   pub n_quality:c_int,
   pub p_facial_data:[c_uchar;512],//值得注意
}
impl FIFacePos{
    pub fn new() -> FIFacePos {
        FIFacePos{
           pt_left_eye:FIPoint::new(),
           pt_right_eye:FIPoint::new(),
           pt_mouth:FIPoint::new(),
           pt_nose:FIPoint::new(),                  
           f_angle:FIFaceAngle::new(),
           n_quality:0 as c_int,
           p_facial_data: unsafe {mem::uninitialized()},//
        }
     }
}

#[link(name = "库文件名")]
extern {
   pub fn fi_detect_face( n_channel_id:c_short,  bpp:c_int,  n_width:c_int,  n_height:c_int, pfps:*mut FIFacePos ,n_max_face_nums: c_int , n_sample_size:c_int )->c_int;
}
调用
extern crate libc;
use libc::{c_int,c_ulonglong,c_long,c_float,c_uchar,c_short};
use std::mem;
let max_face_num=10;
let mut face_poses = Vec::new();

for _ in 0..max_face_num {
    face_poses.push(FIFacePos::new());
}
let face_num: i32 = unsafe {
   fi_detect_face(0 as c_short,24 as c_int, w as c_int ,h as c_int,face_poses.as_mut_ptr(),max_face_num,640 as c_int ) as i32
};

3将Rust编译成库

3.1简单类型

Rust库

extern crate libc;

use libc::c_int;

#[no_mangle]
pub extern "C" fn rs_trigger(v1:c_int,v2:c_int) -> c_int {
  return v1 + v2;
}

调用

#ifdef _WIN64
#define __EXT __declspec(dllexport)
#elif _WIN32
#define __EXT __declspec(dllexport)
#else
#define __EXT extern
#endif
//将dll拷贝到exe相同的目录
#pragma comment (lib,"**/target/release/lib**.dll.lib")

#ifdef __cplusplus  
extern "C" //C++这个一定要加上
#endif 
__EXT int  add(int v1, int v2);


add(1,2);

3.2复杂类型

待续

小结

只在windows 上进行测试,linux 未知

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个可能的 Rust 结构体和 C 接口的示例: 在 Rust 定义结构体: ```rust use std::ffi::{CString, c_void}; use std::os::raw::{c_char, c_int}; use std::slice; use std::collections::BTreeSet; use std::cmp::Ordering; #[repr(C)] pub struct RustStruct { pub string_field: String, pub btree_set_field: BTreeSet<String>, } impl PartialEq for RustStruct { fn eq(&self, other: &Self) -> bool { self.string_field == other.string_field } } impl Eq for RustStruct {} impl PartialOrd for RustStruct { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } impl Ord for RustStruct { fn cmp(&self, other: &Self) -> Ordering { self.string_field.cmp(&other.string_field) } } #[no_mangle] pub extern "C" fn create_rust_struct(string_field: *const c_char, set_field: *const *const c_char, set_len: c_int) -> *mut RustStruct { let string_field = unsafe { CString::from_raw(string_field as *mut c_char) }; let string_field = string_field.into_string().unwrap(); let set_field = unsafe { slice::from_raw_parts(set_field, set_len as usize) }; let set_field = set_field.iter().map(|&x| { let s = unsafe { CString::from_raw(x as *mut c_char) }; s.into_string().unwrap() }).collect::<BTreeSet<String>>(); let rust_struct = RustStruct { string_field, btree_set_field: set_field, }; Box::into_raw(Box::new(rust_struct)) } #[no_mangle] pub extern "C" fn free_rust_struct(rust_struct: *mut RustStruct) { unsafe { Box::from_raw(rust_struct) }; } ``` 在 C 定义接口: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <stdint.h> #include <limits.h> struct RustStruct { char* string_field; char** btree_set_field; int btree_set_len; }; extern struct RustStruct* create_rust_struct(const char* string_field, const char** btree_set_field, int btree_set_len); extern void free_rust_struct(struct RustStruct* rust_struct); int main() { const char* string_field = "hello"; const char* btree_set_field[] = {"world", "rust", "c"}; struct RustStruct* rust_struct = create_rust_struct(string_field, btree_set_field, sizeof(btree_set_field)/sizeof(btree_set_field[0])); for (int i = 0; i < rust_struct->btree_set_len; i++) { printf("%s\n", rust_struct->btree_set_field[i]); } free_rust_struct(rust_struct); return 0; } ``` 这个示例,在 Rust 定义了一个结构体 RustStruct,其包含一个 String 类型的字段和一个 BTreeSet<String> 类型的字段。然后,通过 create_rust_struct 函数,将 RustStruct 结构体的实例从 Rust 代码传递到 C 代码。在 C ,使用 std::list 将 Vec<String> 转换为列表,并输出列表的内容。最后,通过 free_rust_struct 函数释放 RustStruct 结构体的实例。需要注意的是,由于 C++ 没有 BTreeSet,因此在此示例使用了 std::list。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值