Julia-C Interface with Non-Basic Types

I am expanding the Julia package, which uses the C library. I need to call some C functions from Julia. They look something like this:

struct contained { int x; int y; int z; }; struct mystruct { int n; contained* arr; }; mystruct* mk_mystruct(int n, contained* arr); void use_mystruct(mystruct* foo); 

I also declared the corresponding types in Julia:

 type contained x::Int64 y::Int64 z::Int64 end type mystruct n::Int64 arr::Array{contained, 1} end 

In ccall functions that take contained* as an argument, everything works fine, treating contained* as Ptr{Int64} :

 con = fill(0, 5, 3); mys = ccall((:mk_mystruct, "mylib"), Ptr{mystruct}, (Int64, Ptr{Int64}), n, con) 

I suppose this works because contained has the same memory layout as the Int64 array. This is also how it is done elsewhere in the Julia package. But the only way to know the value of the returned mystruct is to dereference it with unsafe_load , after which Julia flies out of segfault. What is the correct way to dereference a pointer in Julia?

The C library also includes pretty print functions, so instead of dereferencing a pointer in Julia, I could treat the pointer as opaque and pass it to this C function:

 void print_mystruct(mystruct* foo, FILE* outputfile) 

In C code, this is called using outputfile=stdout . How would I install this using ccall ? This clearly does not work:

 ccall((:print_mystruct, "mylib"), Void, (Ptr{mystruct}, Ptr{Void}), mys, stdout) 

What should I put in place of Ptr{Void} and stdout ? How does Julia implement I / O in the C interface?

+5
source share
1 answer

When you declare a type in Julia, you must declare the same types as C:

 type contained x::Cint y::Cint z::Cint end type mystruct n::Cint arr::Ptr{contained} end 

The Julia Array{contained, 1} type Array{contained, 1} will match jl_value_t* in C, and the Julia Int type will match intptr_t in C.

I don’t know about the platform agnostic way to get the stdout descriptor, since most platforms require a C header macro extension to find out the real name of the character. For example, on macOS it is renamed to __stdoutp :

 julia> unsafe_load(cglobal(:__stdoutp, Ptr{Void})) Ptr{Void} @0x00007fff751f7348 julia> ccall(:fprintf, Csize_t, (Ptr{Void}, Cstring, Cint...), ans, "hi\n") hi 0x0000000000000003 

You may be interested in checking out the Clang.jl package , which can automatically generate these definitions when parsing header files.

+3
source