C interface for void**

Hello Guys,

A quite simple question on the C API and use with Julia
I want to interface Julia functions with an existing C library cLib. This library has a function(let’s call it cfunction) that creates a buffer and fills it with Cfloat. The issue is that for some (opaque) reasons, they cast the buffer into a void** before filling it.

In another words, the C lines are as follow

float* buff = malloc(N* sizeof(float));
void** ptr	= (void**)&buff;
cfunction(ptr); 

I want to directly interface Julia code with cfunction with ccall, so I try something like that

buff  = Vector{Cfloat}(undef,N);		
ptr	  = Ref(buff):						# The (void**)&buff, that does not do the trick :) 
ccall((:cfunction,cLib),Cvoid,(Ptr{Cvoid},),ptr);  # Calling the function 

Aaaaaand it’s segfault. Any idea to address this ?
Thanks in advance

Without having tested but try it like this.

https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#mapping-c-types-to-julia-1

Ptr{Ptr{Cvoid}}

best regards
Michael

1 Like

Many thank’s for the answer.

The issue if I try to use a Ptr{Ptr{Cvoid}} is that Julia try to convert it, I have to create a Base.unsafe_convert method to pass from Base.RefValue{Array{Float32,1}} to Ptr{Ptr{Nothing}}

and I don’t know how to do this. I try innocently to create a method as

Base.unsafe_convert(T::Type{Ptr{Ptr{Cvoid}}}, t::Base.RefValue{Array{Float32,1}}) = t;

but of course it raise an error:

ERROR: TypeError: in ccall argument 2, expected Ptr{Ptr{Nothing}}, got Base.RefValue{Array{Float32,1}}

Any idea on how to create the convert method ?

I have experimented a bit with your example using only integer values

arr=Int[10,20,30,40,50,60,70,80,90,100]
parr=Ref(arr)
ccall((:cFunction, LIB), Cvoid, (Ptr{Cvoid},Cint), Base.cconvert(Ptr{Ptr{Cvoid}},parr), 10)

my cFunction looks like this

void cFunction(void **ptr, int l){
    int** iPtr = (int**)ptr;
    for (int x=0; x < l; x++){
        printf("Wert : %d\n", *(*iPtr+x));
    }
}

best regards
Michael

1 Like

It seems that ptr should be

buff  = Vector{Cfloat}(undef,N)	
ptr	  = Ref(Ptr{Cvoid}(pointer(buff)))
ccall((:cfunction,cLib),Cvoid,(Ptr{Ptr{Cvoid}},),ptr)
2 Likes

Your example also works for me and looks much clearer :+1:

best regards
Michael

Hello Guys,

Many thanks for these quick answers, it works now :slight_smile:

1 Like