Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Variadic Functions

Rust has no ... parameters and no va_list. A variadic C function is translated as a function whose last parameter is a slice of VaArg, an enum with one variant per kind of value C’s default argument promotions can produce:

#![allow(unused)]
fn main() {
pub enum VaArg {
    Int(i32),
    UInt(u32),
    Long(i64),
    ULong(u64),
    Double(f64),
    RawPtr(*mut c_void),
    Ptr(AnyPtr),
}
}

At a call site every extra argument is converted with .into(), which performs the promotions (char and short to int, float to double) and erases pointers to AnyPtr in the refcount model or *mut c_void in the unsafe model. Inside the function, va_list is a VaList, a cursor over the slice: va_start becomes VaList::new(__args), va_arg(ap, T) becomes ap.arg::<T>(), va_copy is a plain copy of the cursor, and va_end is a no-op:

int sum(int count, ...) {
  va_list ap;
  va_start(ap, count);
  int total = 0;
  for (int i = 0; i < count; i++)
    total += va_arg(ap, int);
  va_end(ap);
  return total;
}

sum(3, 10, 20, 30);
#![allow(unused)]
fn main() {
pub fn sum_0(count: i32, __args: &[VaArg]) -> i32 {
    let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
    (*ap.borrow_mut()) = VaList::new(__args);
    let total: Value<i32> = Rc::new(RefCell::new(0));
    // ...
    (*total.borrow_mut()) += (*ap.borrow_mut()).arg::<i32>();
    // ...
}

sum_0(3, &[10.into(), 20.into(), 30.into()]);
}

arg::<T>() goes through the VaArgGet trait, implemented for the integer and floating types, raw pointers, Ptr<T>, AnyPtr, and FnPtr<T>. Integer variants convert freely among the integer types, as va_arg does with types of the same rank; asking for a pointer where an integer was passed, or the reverse, panics, as does reading past the last argument.

Variadic libc functions such as printf and fcntl are handled by variadic rules, whose bodies receive the same &[VaArg] slice; format_c in the format module consumes one to evaluate a format string.