Clarification on the differences between `Ptr` and `Ref`

I have a question regarding ccall, Ptr, Ref and pointer_to_objref.

Let’s say I have a function that is like so

mutable struct UserData
    x::Int
end

function foo(bar, userdata, err)
    ccall((:foo, liblibrary), Cvoid, (Ptr{Cvoid},), userdata)
end

Is there any difference between the following code? If so, can someone elaborate on what the difference is?

userdata = UserData(1)
r = Ref(userdata)
x = foo(r)

And

userdata = UserData(1)
p = pointer_to_objref(userdata)
x = foo(p)

The documentation says

For C code accepting pointers, Ref{T} should generally be used for the types of input arguments, allowing the use of pointers to memory managed by either Julia or C through the implicit call to Base.cconvert .

https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#When-to-use-T,-Ptr{T}-and-Ref{T}-1

Why does the documentation say “generally be used for types of input arguments”? What would be exceptions to this general rule? In what situations would it be appropriate to call pointer_to_objref on an instance of a mutable Julia struct?

Yes. The second version is garbage. (i.e. the value you get in C is not usable.)

It’s talking about the argument type in the ccall, i.e. where you have Ptr{Cvoid} and it mosly apply to when you know the type you’ll use so that you can write ccall(.... (Ref{Int}, ...), 1).

Almost never. In the context of ccall the function is there to implement unsafe_convert. Using it would be equivalent to using unsafe_convert. If you don’t have a case where you need unsafe_convert, don’t use pointer_from_objref.

3 Likes