How do I pass each element of a slice as a separate argument to a variadic C function?

倖福魔咒の 提交于 2019-11-29 15:22:28
Shepmaster

You don't, at least not yet, and I'd wager probably never.

To be able to do this, you'd need two key abilities, both of which are outside of your control:

  1. Redis needs to provide a function that accepts a va_list argument, not just a ....

    It's strange that Redis doesn't already provide such a function, but perhaps this is a sign that other people implementing modules avoid the problem entirely.

  2. Rust needs to provide a way to construct the va_list argument.

    While it looks like RFC 2137 will introduce a VaList type, the proposed API does not provide a way to create one or set values in it.

Note that you can't do what you want, even in C (at least not easily or portably).


What can you do instead? Assuming that you are implementing the code that consumes the variadic arguments, you can remove the variation from your call. A collection of items in C is just a pointer and a length, so pass that instead:

extern "C" {
    fn call(n_args: i32, ...);
}

fn x(args: &[i32]) {
    unsafe { call(2, args.len(), args.as_ptr()) };
}

If you didn't have control of what reads the code on the other side, one possible (read: terrible) idea is to pattern match on some "large enough" subset of the slice and dispatch off to the variadic function:

extern "C" {
    fn call(n_args: i32, ...);
}

fn x(args: &[i32]) {
    unsafe {
        match args {
            [] => call(0),
            [a] => call(1, a),
            [a, b] => call(2, a, b),
            _ => panic!("Didn't implement this yet"),
        }
    }
}

See also:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!