I am extending a Julia package that uses a 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 have 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
To ccall
functions which take a contained*
as an argument, everything works fine treating the 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 an array of Int64s. This is also how it is done elsewhere in the Julia package. But the only way I know to check the value of the returned mystruct
is to dereference it with unsafe_load
, at which point Julia crashes from a segfault. What is the right way to dereference a pointer in Julia?
The C library also includes pretty-printing functions, so instead of dereferencing the pointer in Julia I could treat the pointer as opaque and pass it back to this C function:
void print_mystruct(mystruct* foo, FILE* outputfile)
In the C code, this is called with outputfile=stdout
. How would I set this up with ccall
? This obviously does not work:
ccall((:print_mystruct, "mylib"), Void, (Ptr{mystruct}, Ptr{Void}), mys, stdout)
What should I put instead of Ptr{Void}
and stdout
? How does Julia implement I/O in the C interface?
When you declare the 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 type Array{contained, 1}
would correspond to jl_value_t*
in C and the Julia type Int
would correspond to intptr_t
in C.
I don't know of a platform-agnostic way to get a handle to stdout
, as most platforms require expanding a C header macro to find out the real symbol name. For example, on macOS, it gets 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 from parsing the header files.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With