Passing a list of arguments to a varargs C function

I can call a varargs C function like printf as follows

julia> ccall(:printf, Int32, (Cstring, Int32...), "%d %d\n", 42, 43)
42 43
6

However, if I try to pass a list of arguments, I get a strange error

julia> x = Int32[42, 43];

julia> ccall(:printf, Int32, (Cstring, Int32...), "%d %d\n", x...)
ERROR: MethodError: no method matching cconvert(::Type{Int32}, ::Int32, ::Int32)
Closest candidates are:
  cconvert(::Type, ::Any) at essentials.jl:149
  cconvert(::Type{Int32}, ::RawFD) at libc.jl:24
  cconvert(::Type{#s2} where #s2<:Ptr, ::Any) at essentials.jl:150
Stacktrace:
 [1] anonymous at ./<missing>:?

This looks like a ccall limitation, but I wonder whether there is a work-around.

1 Like

No. Function call with unknown number of argument requires very special code generation. AFAICT LLVM does not support it. libffi should though you should be better off tweaking/picking a different C-API.

Unfortunately, I don’t control the C API and for one function there is no alternative. However, the varargs are all of the same type and in practice only a small number is used. My work-around is to define a series of methods one for each number of varargs. This is a rather tedious repetition of lines like

f(x1::Ptr{T}) = ccall(:f, Int, (Ptr{T}, ) x1, C_NULL)
f(x1::Ptr{T}, x2::Ptr{T}) = ccall(:f, Int, (Ptr{T}, Ptr{T}), x1, x2,  C_NULL)
...

and I wonder if I can replace that with some smart metaprogramming.

1 Like