我从 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<c_char> = 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# 中,我想调用获取版本函数,获取字符串,然后将其传递回 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 ;
}
rustffi_get_version
中的IntPtr
可以成功转换为 C# 托管字符串类型。 tempString
和 ver
都不错。
当 rustffi_get_version_free(tempPointer)
运行时,它会抛出一个异常,提示 stack unbalanced:
A call to PInvoke function 'rustFfiLibrary!rustFfiLibrary.RustFfiApi::rustffi_get_version_free' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
sizeof(IntPtr)
和 sizeof(char *)
在我的系统上都是 4。另外,IntPtr
用于返回值;为什么它不能用作输入参数?
最佳答案
extern "C"fn
在 Rust 中表示该函数使用 C 调用约定。
C# 期望 P/Invoke 函数默认使用 stdcall 调用约定。
您可以告诉 C# 使用 C 调用约定:
[DllImport("rustffilib.dll", CallingConvention = CallingConvention.Cdecl)]
或者,您可以在 Rust 端使用 extern "stdcall"fn
。
关于c# - 如何释放 C# 中从 Rust 返回的字符串的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34737626/