2016-11-04 20 views
5

mexPrintf, podobnie jak printf, akceptuje listę argumentów varargs. Nie wiem, jaki jest najlepszy sposób na owinięcie tego w Rust. Jest RFC for variadic generics, ale co możemy zrobić dzisiaj?Jak zawinąć wywołanie do funkcji FFI, która używa VarArgs w Rust?

W tym przykładzie chcę wydrukować liczbę wejść i wyjść, ale funkcja opakowana po prostu drukuje śmieci. Jakiś pomysł jak to naprawić?

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); 
} 

Aktualizacja: pomyliła się variable list of arguments z va_list. Uniknę obu, jeśli będę mógł i w tej sytuacji, zamierzam zrobić formatowanie rdzy w Rust, zanim przejdę do współdziałania. Oto co pracował dla mnie w tym przypadku:

#![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

Czy masz na myśli, że mexPrintf akceptuje zmienną liczbę argumentów takich jak 'printf' lub' va_list' takich jak 'vprintf'? Jeśli poprzedni, musisz przekazać liczbę całkowitą bezpośrednio, a nie jako wskaźnik do niej. –

+0

Dzięki @ChrisEmerson, niestety zdezorientowałem dwóch. Dziękuję za pomoc w wyjaśnieniu tego. –

Odpowiedz

4

Wbrew powszechnemu przekonaniu, że jest to możliwe do wywołanie funkcji o zmiennej liczbie argumentów/vararg, które zostały zdefiniowane w C. To nie znaczy, że zrobienie tego jest bardzo łatwe i zdecydowanie łatwiej jest zrobić coś złego, ponieważ istnieje jeszcze mniej typów kompilatora, z którymi można sprawdzić swoją pracę.

Oto przykład połączenia pod numer printf. Mam zakodowane prawie wszystko:

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() 
} 

Zauważ, że muszę bardzo wyraźnie upewnić mój format string i argumenty są wszystkie właściwe rodzaje i ciągi są znakiem NUL.

Zwykle będziesz używać narzędzi takich jak 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 Test kompilator apartament posiada również an example of calling a variadic function.


Słowo ostrzeżenia specjalnie dla printf -jak funkcji: kompilator C-pisarze sobie sprawę, że ludzie zepsuć ten szczególny typ zmiennej liczbie argumentów wywołania funkcji cały czas. Aby temu zaradzić, zakodowali specjalną logikę, która analizuje ciąg formatu i próbuje sprawdzić typy argumentów względem typów oczekiwanych przez łańcuch formatów. Kompilator Rust nie sprawdzi dla ciebie twoich napisów w stylu C!

Powiązane problemy