RUST 调用 C++的 lib 请教

1次阅读

共计 3363 个字符,预计需要花费 9 分钟才能阅读完成。

新人学习 rust ffi,实在搞不定,特来请教一下
下面段代码主要是实现一个简单的字符串然后通过 FFI 调用 hyperscan(这是一个 C++ 写的库,我通过 lib 调用,完全静态编译)的正则表达式同时匹配多个 pattern,然后打印每一个 pattern 出现的第一个位置即可,如果没出现打印 -1。
但是这个代码我怎么改都是 -1 或者 0,就是不能有正确结果,我问了多个 AI,但是都始终无法解决这个问题,所以想向大神请教一下,非常感谢。

运行结果如下:

Hyperscan 版本: 5.4.2 2024-10-06
模式 "test" 未出现,位置: -1
模式 "string" 未出现,位置: -1
模式 "example" 未出现,位置: -1
模式 "中文" 未出现,位置: -1

完整代码如下:

use std::ffi::{CStr, CString};
use std::os::raw::{c_int, c_uint, c_void};
use std::ptr;

const HS_MODE_BLOCK: c_uint = 1;
const HS_FLAG_LITERAL: c_uint = 1 << 10; // 添加 HS_FLAG_LITERAL 常量

#[link(name = "hs")]
extern "C" {fn hs_version() -> *const i8;

    pub fn hs_compile_multi(
        expressions: *const *const i8,
        flags: *const c_uint,
        ids: *const c_uint,
        elements: c_uint,
        mode: c_uint,
        platform: *const c_void,
        db: *mut *mut hs_database_t,
        compile_err: *mut *mut hs_compile_error_t,
    ) -> c_int;

    pub fn hs_alloc_scratch(
        db: *const hs_database_t,
        scratch: *mut *mut hs_scratch_t,
    ) -> c_int;

    pub fn hs_free_scratch(scratch: *mut hs_scratch_t,) -> c_int;

    pub fn hs_scan(
        db: *const hs_database_t,
        data: *const i8,
        length: c_uint,
        flags: c_uint,
        scratch: *mut hs_scratch_t,
        match_event_handler: Option<
            extern "C" fn(
                id: c_uint,
                from: u64,
                to: u64,
                flags: c_uint,
                context: *mut c_void,
            ) -> c_int,
        >,
        context: *mut c_void,
    ) -> c_int;

    pub fn hs_free_database(db: *mut hs_database_t) -> c_int;

    pub fn hs_free_compile_error(error: *mut hs_compile_error_t);
}

pub enum hs_database_t {}
pub enum hs_scratch_t {}

#[repr(C)]
pub struct hs_compile_error_t {
    pub message: *const i8,
    pub expression: c_int,
}

const HS_SUCCESS: c_int = 0;

extern "C" fn event_handler(
    id: c_uint,
    from: u64,
    _to: u64,
    _flags: c_uint,
    context: *mut c_void,
) -> c_int {
    unsafe {
        let positions = context as *mut u64;
        let pos_ptr = positions.add(id as usize);
        if *pos_ptr == u64::MAX {*pos_ptr = from;}
    }
    0
}

fn main() {
    unsafe {
        // 获取并打印 Hyperscan 版本
        let version = hs_version();
        let c_str = CStr::from_ptr(version);
        let str_slice = c_str.to_str().unwrap();
        println!("Hyperscan 版本: {}", str_slice);

        // 定义要匹配的模式列表
        let patterns = vec!["test", "string", "example", "中文"];

        // 将模式转换为 CString
        let c_patterns: Vec = patterns
            .iter()
            .map(|s| CString::new(*s).unwrap())
            .collect();

        // 创建 expressions、flags、ids 数组
        let expressions: Vec<*const i8> = c_patterns.iter().map(|s| s.as_ptr()).collect();

        // 使用 HS_FLAG_LITERAL 标志
        let flags: Vec = vec![HS_FLAG_LITERAL; patterns.len()];

        let ids: Vec = (0..patterns.len() as c_uint).collect();

        // 编译模式
        let mut db: *mut hs_database_t = ptr::null_mut();
        let mut compile_err: *mut hs_compile_error_t = ptr::null_mut();

        let compile_result = hs_compile_multi(expressions.as_ptr(),
            flags.as_ptr(),
            ids.as_ptr(),
            patterns.len() as c_uint,
            HS_MODE_BLOCK,
            ptr::null(),
            &mut db,
            &mut compile_err,
        );

        if compile_result != HS_SUCCESS {if !compile_err.is_null() {
                let err = &*compile_err;
                let message = CStr::from_ptr(err.message).to_string_lossy();
                println!("编译错误: {}", message);
                hs_free_compile_error(compile_err);
            } else {println!("未知的编译错误");
            }
            return;
        }

        // 分配 scratch 空间
        let mut scratch: *mut hs_scratch_t = ptr::null_mut();
        let alloc_result = hs_alloc_scratch(db, &mut scratch);
        if alloc_result != HS_SUCCESS {println!("hs_alloc_scratch 失败");
            hs_free_database(db);
            return;
        }

        // 定义输入字符串
        let input = "This is a test string for example purposes 中文测试.";

        // 初始化匹配位置数组
        let mut match_positions: Vec = vec![u64::MAX; patterns.len()];

        // 执行扫描
        let scan_result = hs_scan(
            db,
            input.as_ptr() as *const i8,
            input.len() as c_uint,
            0,
            scratch,
            Some(event_handler),
            match_positions.as_mut_ptr() as *mut c_void,);

        if scan_result != HS_SUCCESS {println!("hs_scan 失败,错误代码: {}", scan_result);
            hs_free_scratch(scratch);
            hs_free_database(db);
            return;
        }

        // 输出结果
        for (i, pattern) in patterns.iter().enumerate() {let pos = match_positions[i];
            if pos != u64::MAX {println!("模式"{}"首次出现位置: {}", pattern, pos);
            } else {println!("模式"{}"未出现,位置: -1", pattern);
            }
        }

        // 释放资源
        hs_free_scratch(scratch);
        hs_free_database(db);
    }
}

正文完
 0