简体   繁体   English

Rust 字符串和 C 可变参数函数

[英]Rust Strings and C variadic functions

I need pass a vector of Rust string to a C variadic function .我需要将 Rust 字符串的向量传递给C 可变参数函数 But I can't figure out what is the expected( CString , [u8] ..) format.但我无法弄清楚预期的( CString[u8] ..)格式是什么。

References:参考:

My api16 example code version:我的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));

Result of version of api16 : api16版本的结果:

event_buffer: 'evento' 8
result_buffer: '' 8

My Rust code:我的生锈代码:

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()));

Result of my Rust code:我的 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"

I already tried use CString or CStr , like here .我已经尝试使用CStringCStr ,就像这里一样。

What am I doing wrong?我究竟做错了什么?

You're doing multiple things wrong in the rust version.你在 Rust 版本中做错了很多事情。 For the first two arguments, you're intended to pass a pointer to a location that can hold a single pointer to a byte buffer.对于前两个参数,您打算将指针传递到一个位置,该位置可以保存指向字节缓冲区的单个指针。 Instead, you're passing in a pointer to a byte buffer, so a pointer is getting written into that buffer, which isn't what you want.相反,您传递了一个指向字节缓冲区的指针,因此指针被写入该缓冲区,这不是您想要的。

Secondly, the id_count parameter corresponds to the number of strings you're passing as the variadic parameters, rather than the length of a single variadic string, meaning your c code just reads a bunch of uninitialized memory, which definitely isn't what you want.其次, id_count参数对应于您作为可变参数传递的字符串数,而不是单个可变字符串的长度,这意味着您的 C 代码只是读取一堆未初始化的内存,这绝对不是您想要的. Additionally, that string does need to be null-terminated, and it isn't in your example, you do need CString .此外,该字符串确实需要以 null 结尾,并且它不在您的示例中,您确实需要CString What you really want is something like this:你真正想要的是这样的:

use std::ffi::{c_char, c_long, c_ushort, CStr, CString};
use std::ptr;
use std::slice;
use std::str;
fn main() {
    let mut event_buffer = ptr::null_mut();
    let mut result_buffer = ptr::null_mut();
    let names = CString::new("evento").unwrap();
    let len = unsafe {
        isc_event_block(
            &mut event_buffer,
            &mut result_buffer,
            1,
            names.as_ptr() as *mut c_char,
        )
    };
    debug_assert!(!event_buffer.is_null() && !result_buffer.is_null());
    let event_slice = unsafe { slice::from_raw_parts(event_buffer.cast(), len as usize) };
    let result_slice = unsafe { slice::from_raw_parts(event_buffer.cast(), len as usize) };
    let event_str = str::from_utf8(event_slice).unwrap();
    let result_str = str::from_utf8(result_slice).unwrap();
    println!("event: {event_str}");
    println!("result: {result_str}");
}

Playground 操场

Adding a simple stub to print the string passed in, and write a couple of strings into the buffers, I got this:添加一个简单的存根来打印传入的字符串,并将几个字符串写入缓冲区,我得到了这个:

"evento"
event: some events
result: some events

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM