【问题标题】:The best way in Rust to return a dynamic string from extern "C" method to be consumed by C or C++Rust 中从 extern "C" 方法返回动态字符串以供 C 或 C++ 使用的最佳方法
【发布时间】:2016-02-14 08:38:02
【问题描述】:

这个有点相关,但答案对我来说不是很清楚: C library freeing a pointer coming from Rust

书中还有一个example with static string,但是它不能与动态创建的字符串一起正常工作。

我终于找到了这个解决方案,调用 C/C++ 代码为要接收的字符串分配并随后释放内存,但它看起来有些难看,必须为未知字符串定义一些特定的长度:

#[no_mangle]
pub extern fn rs_string_in_string_out(s_raw: *const c_char, out: *mut c_char) -> c_int {
    // take string from the input C string
    if s_raw.is_null() { return 0; }

    let c_str: &CStr = unsafe { CStr::from_ptr(s_raw) };
    let buf: &[u8] = c_str.to_bytes();
    let str_slice: &str = std::str::from_utf8(buf).unwrap();
    let str_buf: String = str_slice.to_owned();

    //produce a new string
    let result = String::from(str_buf + " append from Rust");
    let len = result.len();

    //create C string for output
    let c_result = CString::new(result);

    //write string into out pointer passed by C++ addon
    unsafe{ std::ptr::copy(c_result.unwrap().as_ptr(), out, len); };

    // return result length
    return len as c_int;
}

最好有一些实际返回值,而不是写入可变参数。

【问题讨论】:

  • 最好有一些实际返回值的东西 =>你总是可以创建一个包含char*size_t的C结构并使用作为返回类型;如果 C 没有一体化的结果并且你必须自己编写它,这几乎不是 Rust 的错。
  • 谢谢,马修! C“字符串”末尾有EOF符号就足够了。问题更多是关于解除分配的东西。

标签: c++ c rust


【解决方案1】:

您可以使用 CString 上的 into_raw 将其转换为原始指针,然后您可以从函数中返回。

你不应该依赖 Rust 使用系统分配器。无法保证您的 Rust 代码将链接到与 C/C++ 代码相同的 free。例如,在 Windows 上,有 msvcrtmsvcr80msvcr90 等,它们都管理单独的堆。因此,您的库仍应提供一个函数来释放它分配的内存。对于CString,你应该使用CString::from_raw(你不需要使用结果,Rust 会自动丢弃它,这将释放堆上的字符串)。

【讨论】:

    【解决方案2】:

    不确定它是否是全新的,但文档指出 (https://doc.rust-lang.org/book/custom-allocators.html#default-allocator),库默认使用 alloc_system,这意味着我们可以在 C/C++ 中免费使用。也可以在头部添加#![feature(alloc_system)] 感觉更安全。

    【讨论】:

      猜你喜欢
      • 2011-03-20
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多