2016-11-04 73 views
5

mexPrintf,就像printf一样,接受参数的可变参数列表。我不知道什么是最好的方式来包装在Rust。有一个RFC for variadic generics,但我们今天能做什么?如何将调用包装到在Rust中使用VarArgs的FFI函数?

在这个例子中,我想打印输入和输出的数量,但是打包函数只是打印垃圾。任何想法如何解决这个问题?

enter image description here

#![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); 
} 

更新:我混淆了一个variable list of argumentsva_list。如果可以的话,我会尽量避免这两种情况,在这种情况下,我只需在Rust中进行字符串格式化,然后再将它传递给interop。下面是我在这种情况下,什么工作:

#![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)); 
} 

enter image description here

+3

你的意思是mexPrintf接受像'printf'这样的可变数量的参数,或者''vprintf''这样的'va_list'?如果前者需要直接传递整数而不是指向它的指针。 –

+0

谢谢@ChrisEmerson,我很遗憾地感到困惑。感谢您帮助解决问题。 –

回答

4

流行的看法相反,有可能在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() 
} 

请注意,我必须非常明确地确保我的格式字符串和参数都是正确的类型和字符串是NULL结尾的。

通常情况下,你会使用工具,如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) 
} 

锈病编译器测试套件也有an example of calling a variadic function


专门为printf样功能提醒一句:C编译器编写者意识到,人们搞砸了这种特殊类型的可变参数函数调用所有的时间的。为了解决这个问题,他们编码了一些特殊的逻辑来分析格式字符串,并试图根据格式字符串预期的类型检查参数类型。 Rust编译器不会检查你的C风格格式字符串!

相关问题