Ok, I originally badly screwed up my formulation of this question (it's more than a year now since I seriously wrote C++ code and I have pretty limited experience with pure C), so let's try again.
Some C code is written to expect you to do something like the following
void* p;
create_new_thing(&p); //p is now a new thing
do_stuff_to_thing(p); //something happened to p
My question is how to create the object p
in Julia. Right now I believe the answer to be
p = Ref{Ptr{Void}}()
ccall((:create_new_thing, :lib), Void, (Ptr{Ptr{Void}},), p)
ccall((:do_stuff_to_thing, :lib), Void, (Ptr{Void},), p)
Furthermore, I believe the same code but with p
declared instead as p = Array(Ptr{Void}, 1)
also works.
I do however find the whole distinction between Ref
and Ptr
in Julia very confusing, mostly because they seem to get converted between each other in ways I cannot keep track of.
void pointer in C. The void pointer in C is a pointer which is not associated with any data types. It points to some data location in the storage means points to the address of variables.
Pointers contained in C structs should be represented as fields of type Ptr {T} within the corresponding Julia struct types designed to mimic the internal structure of corresponding C structs.
Julia objects do not have first-class memory addresses like C objects do, so we must use p = Ref {Ptr {Void}} () in Julia to get a memory address. This object, as a ref, behaves like &p in C. That means to get the object itself, p in C, we need to use p [] in Julia.
Whenever you have created a pointer to Julia data, you must ensure the original data exists until you have finished using the pointer. Many methods in Julia such as unsafe_load and String make copies of data instead of taking ownership of the buffer, so that it is safe to free (or alter) the original data without affecting Julia.
Your code looks almost fine. But be careful! Any small error, like the one you have here, can cause a segmentation fault:
p = Ref{Ptr{Void}}()
ccall((:create_new_thing, :lib), Void, (Ptr{Ptr{Void}},), p)
ccall((:do_stuff_to_thing, :lib), Void, (Ptr{Void},), p)
# error here ^
The correct way to do it is
p = Ref{Ptr{Void}}()
ccall((:create_new_thing, :lib), Void, (Ptr{Ptr{Void}},), p)
ccall((:do_stuff_to_thing, :lib), Void, (Ptr{Void},), p[])
# fixed ^
The easiest way to understand where to use p
and p[]
is to think of the corresponding C code. In C, we write
void *p;
create_new_thing(&p)
do_stuff_to_thing(p)
Julia objects do not have first-class memory addresses like C objects do, so we must use p = Ref{Ptr{Void}}()
in Julia to get a memory address. This object, as a ref, behaves like &p
in C. That means to get the object itself, p
in C, we need to use p[]
in Julia.
So the equivalent in Julia is
p = Ref{Ptr{Void}}() # this p corresponds to &p in C
ccall(:create_new_thing, ..., p) # like &p
ccall(:do_stuff_to_thing, ..., p[]) # like *(&p); that is, like p
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