Consider the following C API:
struct Options {
    uint32_t a;
    uint32_t b;
    void* extra;
};
struct OptionsExtra {
    uint32_t c;
    uint32_t d;
};
void foo(struct Options const* options);
It can be used from C as follows:
foo(&(struct Options) {
    .a = 1,
    .b = 2,
    .extra = &(struct OptionsExtra) {
        .c = 3,
        .d = 4,
    }
});
I redeclared this API in Julia:
struct Options
    a::UInt32
    b::UInt32
    extra::Ptr{Cvoid}
end
struct OptionsExtra
    c::UInt32
    d::UInt32
end
function foo(options)::Cvoid
    ccall((:foo, lib), Cvoid, (Ref{Options},), options)
end
How should I construct extra pointer in a call to foo?
extra = OptionsExtra(3, 4)
foo(Options(1, 2, #= what goes here? =#))
pointer function only works with arrays and pointer_from_objref only with mutable objects.
As a workaround I can put extra in an array:
extra = [OptionsExtra(3, 4)]
GC.@preserve extra foo(Options(1, 2, pointer(extra)))
But this seems overcomplicated and suboptimal as it involves heap allocation while C version allocates everything on the stack.
Is there any better way to do this?