2016-11-04 3 views
5

mexPrintf, как и printf, принимает список аргументов varargs. Я не знаю, как лучше всего обернуть это в Rust. Существует RFC for variadic generics, но что мы можем сделать сегодня?Как обернуть вызов функции FFI, которая использует VarArgs в Rust?

В этом примере я хочу напечатать количество входов и выходов, но обернутая функция просто печатает мусор. Любая идея, как это исправить?

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 arguments с va_list. Я собираюсь избежать обоих, если смогу и в этой ситуации, я просто собираюсь выполнить форматирование строк в 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)); 
} 

enter image description here

+3

Вы имеете в виду, что mexPrintf принимает переменное количество аргументов, таких как 'printf', или' va_list' как 'vprintf'? Если первое вам нужно передать целое число напрямую, а не как указатель на него. –

+0

Спасибо @ChrisEmerson, я, к сожалению, получил два смущения. Спасибо, что помогли прояснить это. –

ответ

4

Вопреки распространенному мнению, можно вызова функций VARIADIC/vararg, которые были определены в 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) 
} 

Ржавчина тест Compiler Suite также имеет an example of calling a variadic function.


Слово предупреждения специально для printf -как функций: C компилятор пишущие поняли, что люди ввернуть этот конкретный тип вызова VARIADIC функции все время. Чтобы справиться с этим, они закодировали специальную логику, которая анализирует строку формата и пытается проверить типы аргументов на типы, ожидаемые в формате. Компилятор Rust не будет проверять ваши строки формата C для вас!

Смежные вопросы