Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

the proper way to declare C void pointers in Julia

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.

like image 608
Expanding Man Avatar asked Oct 19 '16 20:10

Expanding Man


People also ask

What is a void pointer in C?

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.

What is the best way to represent a pointer in Julia?

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.

How do I get the memory address of an object in Julia?

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.

How do I free the original data in a Julia pointer?

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.


1 Answers

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
like image 165
Fengyang Wang Avatar answered Sep 20 '22 13:09

Fengyang Wang