2016-11-04 63 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風格格式字符串!

相關問題