9

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.

mkj
  • 2,761
  • 5
  • 24
  • 28
  • Detail: with `void* p;`, `p` is a "new thing" (object). `create_new_thing(&p);` allows the function to _assign_ `p` a value. Good luck with Julia. – chux - Reinstate Monica Oct 19 '16 at 20:15
  • Understood, the reason I wasn't using the word object is that I was apprehensive about being very specific. One could do this with, say, an immutable numeric type. – Expanding Man Oct 19 '16 at 20:52
  • In C, _object_ is the _general_ term for "region of data storage ..., the contents of which can represent values" like characters, integers, floating point, pointers, arrays, structures, unions, and constants. Just about anything that can be pointed to except functions. – chux - Reinstate Monica Oct 19 '16 at 20:57

1 Answers1

10

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
Fengyang Wang
  • 11,901
  • 2
  • 38
  • 67
  • 1
    The first `ccall` signature should probably also be `Ref{Ptr{Void}}`, instead of `Ptr{Ptr{Void}}`: http://docs.julialang.org/en/release-0.5/manual/calling-c-and-fortran-code/#passing-pointers-for-modifying-inputs – Simon Byrne Oct 19 '16 at 21:48
  • 1
    @SimonByrne From my understanding, they are exactly equivalent in this case, so I just preserved the OP's code. – Fengyang Wang Oct 19 '16 at 22:18
  • 1
    I think they are equivalent at the moment, but the manual recommends `Ref` for mutable pointers. – Simon Byrne Oct 20 '16 at 09:20
  • 1
    Thanks for the help. I think I understand this now, I was definitely thrown by the difference between Ref and Ptr. I think that as far as C knows Ref and Ptr are the same thing. Julia manages the Ref objects, but only up to the boundary with the C calls. – Expanding Man Oct 20 '16 at 13:30
  • Actually I just realized that I was actually doing what you suggested in your answer, I just screwed up the question. I'll guess I should thoroughly look over my code to make sure it's correct everywhere. Thanks. – Expanding Man Oct 20 '16 at 13:49