V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hkhk366
V2EX  ›  Rust

RUST 调用 C++的 lib 请教

  •  
  •   hkhk366 · 28 天前 · 963 次点击

    新人学习 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<CString> = 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<c_uint> = vec![HS_FLAG_LITERAL; patterns.len()];
    
            let ids: Vec<c_uint> = (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<u64> = 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);
        }
    }
    
    
    5 条回复    2024-10-07 22:33:24 +08:00
    PTLin
        1
    PTLin  
       28 天前
    调用 cpp 的库用 https://cxx.rs/ ,cpp 的 api 和 c 不一样,用 extern "C"未必好使。
    gwy15
        2
    gwy15  
       28 天前
    const HS_FLAG_LITERAL: c_uint = 1 << 10; // 添加 HS_FLAG_LITERAL 常量

    这一行的问题,换成其他的可以正常匹配
    gwy15
        3
    gwy15  
       28 天前
    * Compile flag: Don't do any match reporting.
    *
    * This flag instructs Hyperscan to ignore match reporting for this expression.
    * It is designed to be used on the sub-expressions in logical combinations.
    */
    #define HS_FLAG_QUIET 1024

    你给的 flag 会导致 onEvent 不被调用,自然也就不会写入结果
    hkhk366
        4
    hkhk366  
    OP
       28 天前
    @gwy15 谢谢回复,但是我把 HS_FLAG_LITERAL 改成了 0 或者其他值后,输出结果是下面,还是不对,头疼
    Hyperscan 版本: 5.4.2 2024-10-06
    模式 "test" 首次出现位置: 0
    模式 "string" 首次出现位置: 0
    模式 "example" 首次出现位置: 0
    模式 "中文" 首次出现位置: 0
    gwy15
        5
    gwy15  
       28 天前
    @hkhk366 你自己再研究下你的 flag ,应该是你的 event handler 没写对。你在 event handler 里面打印 to 参数是能发现是正确传递了的。这个库我也没用过,你仔细读文档吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   967 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 22:02 · PVG 06:02 · LAX 14:02 · JFK 17:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.