如何生成具有类似 `main` 接口的 FFI 函数?
How do I produce an FFI function with a `main`-like interface?
我正在尝试使用 Rust 与一个古老的平台交互,该平台期望函数以特定的 C 风格格式声明和外部化。
char *func(int argc, char *argv[])
我正在尝试在 Rust 中重现此签名。我需要能够正确解析参数(理想情况下是 Rust 字符串),然后 return 一个任意值作为字符串而不破坏签名。
到目前为止,我有以下内容:
#[no_mangle]
pub extern "C" fn my_function(argc: isize, argv: *const c_char) -> (CString) {
let output: CString = CString::new("Test Output").expect("CString::new failed");
return output;
}
通过接口正确 return 测试字符串,但我无法弄清楚如何将 argv 解析为可用格式,或者我的 argv 实现是否与指定格式正确兼容.我对指针不熟悉,我什至不知道从哪里开始解决这个问题。
您现有的代码存在几个主要问题:
argv: *const c_char
是错误的,因为原始 C 代码是一个指针数组,而不是指向 char 的指针。正确的类型是
argv: *const *const c_char
你不能 return CString
因为那不是 C 知道如何处理的类型。您需要 return *mut c_char
就像 C 函数所做的那样。为此,您使用 output.into_raw()
to unwrap the string and get the underlying *mut c_char
pointer. This also means that you are giving this C code a random pointer, and it can read it as a C string, but it can't free that memory, so you're either leaking that memory, or you need a second function to pass the string back to Rust to be freed later using from_raw
。在这种情况下,我使用 *mut c_char
因为那是 into_raw
returns.
您应该始终对 C 接口中的所有内容使用 c_
类型,包括 argc
,例如
my_function(argc: c_int, argv: *const *const c_char) -> *mut c_char
要处理 args,您需要遍历 argc
值以将每个指针包装到一个 CStr
中,然后您可以使用它而无需担心不安全代码。
总计:
#[no_mangle]
pub extern "C" fn my_function(argc: c_int, argv: *const *const c_char) -> *mut c_char {
let argv: Vec<_> = (0..argc)
.map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)) })
.collect();
// Whatever processing you need to do.
let output = CString::new("Test Output").expect("CString::new failed");
return output.into_raw();
}
并且可能
#[no_mangle]
pub extern "C" fn my_function_free(s: *mut c_char) {
unsafe {
CString::from_raw(s);
}
}
我正在尝试使用 Rust 与一个古老的平台交互,该平台期望函数以特定的 C 风格格式声明和外部化。
char *func(int argc, char *argv[])
我正在尝试在 Rust 中重现此签名。我需要能够正确解析参数(理想情况下是 Rust 字符串),然后 return 一个任意值作为字符串而不破坏签名。
到目前为止,我有以下内容:
#[no_mangle]
pub extern "C" fn my_function(argc: isize, argv: *const c_char) -> (CString) {
let output: CString = CString::new("Test Output").expect("CString::new failed");
return output;
}
通过接口正确 return 测试字符串,但我无法弄清楚如何将 argv 解析为可用格式,或者我的 argv 实现是否与指定格式正确兼容.我对指针不熟悉,我什至不知道从哪里开始解决这个问题。
您现有的代码存在几个主要问题:
argv: *const c_char
是错误的,因为原始 C 代码是一个指针数组,而不是指向 char 的指针。正确的类型是argv: *const *const c_char
你不能 return
CString
因为那不是 C 知道如何处理的类型。您需要 return*mut c_char
就像 C 函数所做的那样。为此,您使用output.into_raw()
to unwrap the string and get the underlying*mut c_char
pointer. This also means that you are giving this C code a random pointer, and it can read it as a C string, but it can't free that memory, so you're either leaking that memory, or you need a second function to pass the string back to Rust to be freed later usingfrom_raw
。在这种情况下,我使用*mut c_char
因为那是into_raw
returns.您应该始终对 C 接口中的所有内容使用
c_
类型,包括argc
,例如my_function(argc: c_int, argv: *const *const c_char) -> *mut c_char
要处理 args,您需要遍历 argc
值以将每个指针包装到一个 CStr
中,然后您可以使用它而无需担心不安全代码。
总计:
#[no_mangle]
pub extern "C" fn my_function(argc: c_int, argv: *const *const c_char) -> *mut c_char {
let argv: Vec<_> = (0..argc)
.map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)) })
.collect();
// Whatever processing you need to do.
let output = CString::new("Test Output").expect("CString::new failed");
return output.into_raw();
}
并且可能
#[no_mangle]
pub extern "C" fn my_function_free(s: *mut c_char) {
unsafe {
CString::from_raw(s);
}
}