如何将Rust字符串向量传递给C可变参数函数isc_event_block?
Rust传递字符串向量给C可变参数函数
isc_event_block的问题 我需要将Rust字符串向量传递给C可变参数函数isc_event_block,但不确定预期的参数格式(比如CString、[u8]等)。相关参考:API参考isc_event_block、extern C声明ibase、调用方式que_events、C示例api16、API实现isc_event_block。
C示例代码(api16版本)
strcpy (ids[0], "evento"); length = (short) isc_event_block((char **) &event_buffer, (char **) &result_buffer, 1, ids[0], 0); printf("event_buffer: '%s' %d\n", event_buffer, sizeof(event_buffer)); printf("result_buffer: '%s' %d\n", result_buffer, sizeof(result_buffer));
C代码运行结果
event_buffer: 'evento' 8 result_buffer: '' 8
我的Rust代码
let mut event_buffer: Vec<u8> = Vec::with_capacity(256); let mut result_buffer: Vec<u8> = Vec::with_capacity(256); let mut len = 0; let names = "evento".to_string(); unsafe { len = self.ibase.isc_event_block()( event_buffer.as_mut_ptr() as *mut _, result_buffer.as_mut_ptr() as *mut _, names.len() as u16, names.as_ptr() ); event_buffer.set_len(len as usize); result_buffer.set_len(len as usize); } println!("{:?} {:?}", len, names); println!("{:x?} {:x?}", event_buffer, result_buffer); println!("{:?} {:?}", String::from_utf8_lossy(&event_buffer.clone()), String::from_utf8_lossy(&result_buffer.clone()));
Rust代码运行结果
12 ["evento"] [e0, 4f, 51, 28, a8, 7f, 0, 0, 0, 0, 0, 0] [0, 50, 51, 28, a8, 7f, 0, 0, 0, 0, 0, 0] "�OQ(�\u{7f}\0\0\0\0\0\0" "\0PQ(�\u{7f}\0\0\0\0\0\0"
我已经尝试使用CString或CStr,但仍然无法解决问题,请问我哪里出错了?
问题分析与解决方案
核心错误点
- 前两个参数类型完全不匹配:C函数
isc_event_block的前两个参数是char**(指向指针的指针),目的是让函数内部分配内存后,把缓冲区的地址写入到传入的指针变量中。但你直接传递了Vec<u8>的起始指针(*mut u8),完全不符合函数的参数要求。 - 可变参数传递错误:C代码中第三个参数是事件数量
1,之后传入事件名称,最后以0作为可变参数的终止符。你的Rust代码错误地将第三个参数设为names.len(),且没有传入终止可变参数的0。 - 字符串格式不符合C标准:Rust的
String::as_ptr()返回的是UTF-8字节指针,但缺少C字符串要求的\0终止符,会导致未定义行为。
修正后的Rust代码
use std::ffi::CString; // ... let mut event_buffer: *mut u8 = std::ptr::null_mut(); let mut result_buffer: *mut u8 = std::ptr::null_mut(); let mut len = 0; // 生成以\0结尾的C风格字符串 let event_name = CString::new("evento").expect("Failed to create CString"); unsafe { len = self.ibase.isc_event_block()( // 传递指向空指针的指针,让C函数写入分配后的缓冲区地址 &mut event_buffer as *mut *mut u8 as *mut _, &mut result_buffer as *mut *mut u8 as *mut _, 1, // 事件数量,对应C代码中的1 event_name.as_ptr(), 0 // 可变参数必须以0结尾 ); // 将C分配的缓冲区转换为Rust Vec,注意后续需按API要求释放内存 let event_vec = Vec::from_raw_parts(event_buffer, len as usize, len as usize); let result_vec = Vec::from_raw_parts(result_buffer, len as usize, len as usize); println!("{:?}", len); println!("{:x?} {:x?}", event_vec, result_vec); println!("{:?} {:?}", String::from_utf8_lossy(&event_vec), String::from_utf8_lossy(&result_vec)); // 根据API文档要求,调用对应的C释放函数(例如isc_free)释放内存 // isc_free(event_buffer); // isc_free(result_buffer); }
关键注意事项
- 参数传递逻辑:必须传入
*mut *mut u8类型的指针,对应C代码中&event_buffer取指针地址的操作,让C函数能将分配好的缓冲区地址回写到你的变量中。 - 可变参数规则:C可变参数函数需要明确的终止标记,这里必须传入
0来结束事件名称列表。 - 内存管理:C函数分配的内存不能直接由Rust的
Vec自动释放,必须按照API文档要求调用对应的C释放函数,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Batels
相关产品推荐
相关产品推荐

