mexPrintf
,就像printf
一样,接受一个参数的varargs列表,但我不知道在Rust中包装它的最佳方法是什么。有一个RFC for variadic generics,但我们今天能做些什么呢?
在这个例子中,我想打印输入和输出的数量,但是包装函数只打印垃圾。知道如何解决这个问题吗?
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate mex_sys;
use mex_sys::mxArray;
use std::ffi::CString;
use std::os::raw::c_int;
use std::os::raw::c_void;
type VarArgs = *mut c_void;
// attempt to wrap mex_sys::mexPrintf
fn mexPrintf(fmt: &str, args: VarArgs) {
let cs = CString::new(fmt).unwrap();
unsafe {
mex_sys::mexPrintf(cs.as_ptr(), args);
}
}
#[no_mangle]
pub extern "system" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *mut *mut mxArray,
) {
let hw = CString::new("hello world\n").unwrap();
unsafe {
mex_sys::mexPrintf(hw.as_ptr());
}
let inout = CString::new("%d inputs and %d outputs\n").unwrap();
unsafe {
mex_sys::mexPrintf(inout.as_ptr(), nrhs, nlhs);
}
mexPrintf("hello world wrapped\n", std::ptr::null_mut());
let n = Box::new(nrhs);
let p = Box::into_raw(n);
mexPrintf("inputs %d\n", p as VarArgs);
let mut v = vec![3];
mexPrintf("vec %d\n", v.as_mut_ptr() as VarArgs);
}
答案 0 :(得分:5)
与流行的看法相反,有可能调用在C中定义的变量/变量函数。这并不意味着这样做很容易,而且它很容易绝对更容易做坏事,因为编译器检查你的工作的类型甚至更少。
以下是调用printf
的示例。我对所有事情都进行了硬编码:
extern crate libc;
fn my_thing() {
unsafe {
libc::printf(b"Hello, %s (%d)\0".as_ptr() as *const i8, b"world\0".as_ptr(), 42i32);
}
}
fn main() {
my_thing()
}
请注意,我必须非常明确地确保我的格式字符串和参数都是正确的类型,并且字符串是NUL终止的。
通常,您会使用CString
之类的工具:
extern crate libc;
use std::ffi::CString;
fn my_thing(name: &str, number: i32) {
let fmt = CString::new("Hello, %s (%d)").expect("Invalid format string");
let name = CString::new(name).expect("Invalid name");
unsafe {
libc::printf(fmt.as_ptr(), name.as_ptr(), number);
}
}
fn main() {
my_thing("world", 42)
}
Rust编译器测试套件也有an example of calling a variadic function。
专门针对printf
的警告 - 类似函数:C编译器编写者意识到人们搞砸了这种特殊类型的可变参数函数一直。为了帮助解决这个问题,他们编写了特殊逻辑来解析格式字符串,并尝试根据格式字符串所期望的类型检查参数类型。 Rust编译器不会为你检查你的C风格格式字符串!
答案 1 :(得分:0)
我混淆了#34变量参数列表"使用va_list
。如果可以的话,我会避免这两种情况,在这种情况下,我会在将Rust传递给interop之前在Rust中进行字符串格式化。在这种情况下,这对我有用:
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate mex_sys;
use mex_sys::mxArray;
use std::ffi::CString;
use std::os::raw::c_int;
// attempt to wrap mex_sys::mexPrintf
fn mexPrintf(text: &str) {
let cs = CString::new(text).expect("Invalid text");
unsafe {
mex_sys::mexPrintf(cs.as_ptr());
}
}
#[no_mangle]
pub extern "C" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *mut *mut mxArray,
) {
mexPrintf(&format!("{} inputs and {} outputs\n", nrhs, nlhs));
}