On Fri, Nov 6, 2015 at 7:21 AM, Chris Cheetham <chipandrud...@gmail.com> wrote: > Hi there, > > I am currently playing with Julia calls from C. I have made some good > progress insofar as calling Julia functions, boxing/unboxing etc. What I am > particularly interested in however is being able to return a type which > consists of a number of Float64s and being able to get/set their values on > the C side. > > For example > > type Example > a::Float64 > b::Float64 > c::Float64 > end > > > Unboxing returns a copy of a value, so no means to then set it and > jl_get_nth_field seems to also do the same. > > > I am able to get a reference to the value using pointer arithmetic by > getting jl_value_t + 1. I'm assuming the raw jl_value_t pointer is the type > pointer? and offsetting by 1 is the pointer to the value? > > Accessing elements in the type seems possible by further offsetting the > pointer jl_value_t + 1 + elementIndex. My question is, is this a safe > assumption to make? Or is there a better way to be doing this that I haven't > spotted yet?
Which version of julia are you using, what you describe sounds like the behavior on 0.3 and things have changed on 0.4 and I would recommand using 0.4 since its newer and is easier to deal with in C (unless you have legacy code to deal with of course). Each object has a tag followed by the data. The tag is a pointer on both 0.3 and 0.4. The data is a C compatible struct. The type of the field is what you declared in the julia code except for non-leaftype (e.g. Any, abstract type, Union) or non pointerfree types (non-immutable non-bitstype, including every type you declared with `type` instead of `immutable` or `bitstype`) in which case the field is a `jl_value_t*` pointer. The layout in the memory is simply [tag][data] The difference in 0.3 and 0.4 is that on 0.3, a `jl_value_t*` points to the tag while on 0.4 a `jl_value_t*` points to the data. (`jl_taggedvalue_t*` points to the tag on 0.4 but you almost never need to deal with it directly). Note that this apply to both the value you get from the julia runtime as well as the value you load from the field in another `jl_value_t*`. Since the data layout is c compatible, after you've got the pointer to the data section, you can either compute the C offset directly or simply cast it to a c structure and access it just like any c structure. If you want to write to a `jl_value_t*` field there's additional consideration because of the generational garbage collector, see the memory management section of the embedding manual[1], which also have a very short example of accessing field of a jl_value_t. For the example you have above, your `jl_value_t + 1` is the pointer to the data section (since I believe `sizeof(jl_value_t) == sizeof(void*)` on 0.3) and the additional offset are the field offset in a c structure. Note that you can calculate the field offset by simply adding field index to the jl_value_t pointer because both Float64 and pointer are 64bit on 64bit architectures, this is not generally true for other data types or other CPUs so the best way to do this is to cast the pointer to the struct type and access the field. [1] http://julia.readthedocs.org/en/latest/manual/embedding/#memory-management > > Thanks, > Chris > > >