Passing an array of structures through `ccall`, clarification

ccall

#1

I tried to follow the discussion in


because i need to solve a similar problem: C-API expects an array of struct.

Do i understand correctly, that there are exactly two options:


#2

Does this help?

julia> struct Foo
         x::Int64
         y::Int64
       end

julia> a = Foo[Foo(1,3), Foo(2,4), Foo(3,5)]
3-element Array{Foo,1}:
 Foo(1, 3)
 Foo(2, 4)
 Foo(3, 5)

julia> p = pointer(a) # don't do this
Ptr{Foo} @0x00000001058f4e50

julia> unsafe_load(p)
Foo(1, 3)

julia> unsafe_load(p+sizeof(Foo))
Foo(2, 4)

julia> unsafe_load(p+sizeof(Foo)*2)
Foo(3, 5)

#3

Maybe. The question was rather, if in the meanwhile something as macros etc. showed up.
My example is a c struct with different c -types -> Long + 2 Doubles (so 4bytes and 2*8bytes) and i learned that you should not expect julia to allocate in consecutive memory.


#4

As long as you know how the macros expand (I assume you’re talking about C macros here), then you shouldn’t have a problem, as Julia structs should match C structs in layout.

The cairo hacks are to work around C unions, which can’t be represented by Julia at the moment.


#5

I think there might be some confusion here, so maybe it helps to be specific about the points of discussion and the struct layout…

  • The struct below has the same layout as such a struct in C.
struct LobingerAStruct
  x::Clong
  y::Cdouble
  z::Cdouble
end
  • The point of the example I shared is that you can store these non-mutable struct objects in an Array and treat the memory as consecutive (respecting the usual ccall memory rules for passing arrays).

  • I think the point of the macros you are referring to is to make working with immutable structs easier in general, but that is a bit orthogonal to whether it is possible to pass an array of structs to C without a shim.


#6

Thank you, this looks much friendlier now. I got confused by your example having two equal Julia types as entries - and the “don’t do this” comment …


#7

Sorry – what I meant was calling pointer was for demo purposes; for real use-cases you should pass the array as indicated in the ccall manual.


#8

raises a little bit the quesion about where and in which manual?
btw:

   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.2 (2017-12-13 18:08 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-pc-linux-gnu

julia> type glyph_t
               index::Clong
               x::Cdouble
               y::Cdouble
       end

julia> gf = [glyph_t(61,0,0), glyph_t(81,31,0)]
2-element Array{glyph_t,1}:
 glyph_t(61, 0.0, 0.0) 
 glyph_t(81, 31.0, 0.0)

julia> p = pointer(gf)
Ptr{glyph_t} @0x00007f3aa321ca10

julia> unsafe_load(p)
glyph_t(139889821507696, 6.91147550098323e-310, 0.0)

is this expected?


#9

Isn’t type a deprecated alias for mutable struct? I belive you want an immutable, a struct.


#10

(facepalm!)

Yes, i do.