Taking the approach from the doc:
You can get a near approximation of a union if you know, a priori, the field that will have the greatest size (potentially including padding). When translating your fields to Julia, declare the Julia field to be only of that type.
That’s not too bad. Here’s a MWE:
/* test.c */
typedef struct abc
{
union {
unsigned int a;
long b;
} ab;
int c;
} ABC, *ABCP;
ABC make1()
{
ABC x;
x.c = 1;
x.ab.b = 2;
return x;
}
ABC make2()
{
ABC x;
x.c = 1;
x.ab.a = 2;
return x;
}
Compile as usual:
$ gcc -fPIC -shared test.c -o libtest.so
In Julia, I can treat the union as a regular long
variable (which is the largest in this example):
julia> const TEST = "/tmp/libtest.so"
"/tmp/libtest.so"
julia> x = ccall((:make1, TEST), ABC, ())
ABC(2, 1)
julia> y = ccall((:make2, TEST), ABC, ())
ABC(5815918277548834818, 1)
So the value returned by make2
is obviously messed up because I should be looking for the int
rather than the long
field. To correct that, I can do some bit twiddling (not my favorite but some people here like it )
julia> UInt64(y.ab)
0x50b64adc00000002
julia> Int32(y.ab & 0x00000000ffffffff)
2
I really need a way to reinterpret the thing so perhaps I just go with a fixed size tuple.
julia> struct ABC2
ab::NTuple{8, Cuchar} # 8 bytes
c::Int32
end
julia> z = ccall((:make2, TEST), ABC2, ())
ABC2((0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00), 1)
julia> reinterpret(Int32, collect(z.ab[1:4]))
1-element Array{Int32,1}:
2
Next, I’ll try to reinterpret to another struct. Hopefully that will work.
Does this all make sense? Is there any better way to approach this?