You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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,但仍然无法解决问题,请问我哪里出错了?


问题分析与解决方案

核心错误点

  1. 前两个参数类型完全不匹配:C函数isc_event_block的前两个参数是char**(指向指针的指针),目的是让函数内部分配内存后,把缓冲区的地址写入到传入的指针变量中。但你直接传递了Vec<u8>的起始指针(*mut u8),完全不符合函数的参数要求。
  2. 可变参数传递错误:C代码中第三个参数是事件数量1,之后传入事件名称,最后以0作为可变参数的终止符。你的Rust代码错误地将第三个参数设为names.len(),且没有传入终止可变参数的0。
  3. 字符串格式不符合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:35:18