This is not forbidden, the forbidden thing is returning address of anything you allocated in the function.
That’s not true, see below.
Yes, your function will take a void**
that’s fine, but if you want to mutate a void*
in a C struct, you don’t define that field as void**
, you’ll just define it as void*
. And you’ll use it as
struct mytype {
double v;
void *ptr;
};
// and some code in a function
mytype *obj;
// ...
somefunction(obj->v, &obj->ptr);
And you can write a exact equivalent in julia.
No this is not necessary.
Also
is fine but also not necessary. The validity of the ::Cdouble
doesn’t rely on the liveness of the ::MyType
. It’s certainly valid code though, just a little over-complicated.
The direct (and invalid!) way to implement the c++ code above in julia would simply be
ccall(somefunction, Cdouble, (Cdouble, Ptr{Ptr{Void}}), obj.v, pointer_to_objref(obj) + fieldoffset(typeof(obj), 2))
The only invalid part of the above code is that pointer_to_objref(obj) + fieldoffset(typeof(obj), 2)
will not keep obj
alive during the call. And the fix would be to somehow keep it alive. This can be acomplished either with @gc_preserve
on 0.7 like
Base.@gc_preserve obj ccall(somefunction, Cdouble, (Cdouble, Ptr{Ptr{Void}}), obj.v, pointer_to_objref(obj) + fieldoffset(typeof(obj), 2))
which will be the preferred way if the convertion is callsite specific. On 0.6 where there’s no @gc_preserve
or if this call convertion is used multiple times, it is preferred to use the unsafe_convert
/cconvert
and you can do this simply by putting that unsafe convert in, well, unsafe_convert
, sth like.
Base.unsafe_convert(::Type{Ptr{Ptr{Void}}}, obj::MyType) = Ptr{Ptr{Void}}(pointer_to_objref(obj) + fieldoffset(typeof(obj), 2))
And simply do
ccall(somefunction, Cdouble, (Cdouble, Ptr{Ptr{Void}}), obj.v, obj)
The use of either Ref{Ptr{Void}}
or Ptr{Ptr{Void}}
is valid and doesn’t really matter. In fact, any Ref
or Ptr
type should work. I usually prefer Ptr
though since Ref
has special meaning and it is better to not mess with it.
And I’ll also add that I can see how this is a failed attempt at translating the C code I translated above. The important thing to note here about the difference between C and julia is that there’s no C reference in julia. Even though it is not called so in C, obj.field
produces a lvalue reference which is why &
on it gives you the address inside obj
. OTOH, obj.field
always produce a rvalue in julia, or in another word, local variable assignment is never significant, you can insert as many of them as you want in the code and they’ll never make any difference in semantics. This means that pointer_from_objref(m.handle)
corresponds to
{
void *handle = m->handle;
return &handle;
}
and it should be easy to see why it doesn’t give you the result you want. That’s also why you need to explicitly take the address of m
in order to get the address of handle
field in m
.