当前位置:  开发笔记 > 编程语言 > 正文

如何释放C#中Rust返回的字符串的内存?

如何解决《如何释放C#中Rust返回的字符串的内存?》经验,为你挑选了1个好方法。

我从Rust中暴露了这两个函数

extern crate libc;

use std::mem;
use std::ffi::{CString, CStr};

use libc::c_char;

pub static FFI_LIB_VERSION: &'static str = env!("CARGO_PKG_VERSION"); // '

#[no_mangle]
pub extern "C" fn rustffi_get_version() -> *const c_char {
    let s = CString::new(FFI_LIB_VERSION).unwrap();
    let p = s.as_ptr();
    mem::forget(s);

    p as *const _
}

#[no_mangle]
pub extern "C" fn rustffi_get_version_free(s: *mut c_char) {
    unsafe {
        if s.is_null() {
            return;
        }

        let c_str: &CStr = CStr::from_ptr(s);
        let bytes_len: usize = c_str.to_bytes_with_nul().len();
        let temp_vec: Vec = Vec::from_raw_parts(s, bytes_len, bytes_len);
    }
}

fn main() {}

它们由C#导入,如下所示

namespace rustFfiLibrary
{
    public class RustFfiApi
    {
        [DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version")]
        public static extern string rustffi_get_version();

        [DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version_free")]
        public static extern void rustffi_get_version_free(string s);

    }
}

返回的字符串的内存rustffi_get_version不再由Rust管理,因为mem::forget已被调用.在C#中,我想调用get version函数,获取字符串,然后将其传递给Rust进行内存释放,如下所示.

public class RustService
{
    public static string GetVersion()
    {
        string temp = RustFfiApi.rustffi_get_version();
        string ver = (string)temp.Clone();

        RustFfiApi.rustffi_get_version_free(temp);

        return ver ;
    }
}

但C#程序在运行时崩溃了rustffi_get_version_free(temp).如何在C#中释放被遗忘的字符串内存?什么应该传递回Rust进行解除分配?

string我没有在C#extern 中定义为参数,而是将其更改为pointer.

[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version")]
public static extern System.IntPtr rustffi_get_version();

[DllImport("rustffilib.dll", EntryPoint = "rustffi_get_version_free")]
public static extern void rustffi_get_version_free(System.IntPtr s);
public static string GetVersion()
{
    System.IntPtr tempPointer = RustFfiApi.rustffi_get_version();
    string tempString = Marshal.PtrToStringAnsi(tempPointer);

    string ver = (string)tempString.Clone();

    RustFfiApi.rustffi_get_version_free(tempPointer);

    return ver ;
}

IntPtrrustffi_get_version可以成功地转换为C#托管字符串类型.tempString并且ver很好.

rustffi_get_version_free(tempPointer)运行时,它抛出一个异常,说栈不平衡:

调用PInvoke函数'rustFfiLibrary!rustFfiLibrary.RustFfiApi :: rustffi_get_version_free'使堆栈失去平衡.这很可能是因为托管PInvoke签名与非托管目标签名不匹配.检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配.

sizeof(IntPtr)并且sizeof(char *)我的系统都是4.另外,IntPtr适用于退货价值; 为什么它不能作为输入参数?



1> Daniel..:

extern "C" fn在Rust中意味着该函数使用C调用约定.C#期望P/Invoke函数默认使用stdcall调用约定.

您可以告诉C#使用C调用约定:

[DllImport("rustffilib.dll", CallingConvention = CallingConvention.Cdecl)]

或者,您可以extern "stdcall" fn在Rust端使用.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有