我从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 ; }
在IntPtr
从rustffi_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
适用于退货价值; 为什么它不能作为输入参数?
extern "C" fn
在Rust中意味着该函数使用C调用约定.C#期望P/Invoke函数默认使用stdcall调用约定.
您可以告诉C#使用C调用约定:
[DllImport("rustffilib.dll", CallingConvention = CallingConvention.Cdecl)]
或者,您可以extern "stdcall" fn
在Rust端使用.