Open nickbclifford opened 3 years ago
Does that mean, in C, that the array is inlined in the struct?
The array is inlined in the struct. There is no extra pointer. Maybe you could take the struct pointer, offset to that member and cast types. It will be safe.
This works:
@[Link(ldflags: "#{__DIR__}/list.o")]
lib LibList
struct ListT
length : LibC::UInt
data : LibC::Int
end
fun new_list : ListT*
end
list_ptr = LibList.new_list
length = list_ptr.value.length
data = (list_ptr.as(LibC::UInt*) + 1).as(LibC::Int*)
p Slice.new(data, length)
It's not ideal but it gets the job done.
Alternatively I think pointerof(list_ptr.value.data)
should work, but it currently triggers a compiler bug.
This works as well
@[Extern]
struct ListT
@length : LibC::UInt = 0
@data : LibC::Int = 0
def to_slice
Slice.new(pointerof(@data), @length)
end
end
@[Link(ldflags: "#{__DIR__}/list.o")]
lib LibList
fun new_list : ListT*
end
list_ptr = LibList.new_list
p list_ptr.value.to_slice
It works!
Also this:
@[Link(ldflags: "#{__DIR__}/list.o")]
lib LibList
struct ListT
length : LibC::UInt
data : LibC::Int
end
fun new_list : ListT*
end
struct LibList::ListT
def to_slice
Slice.new(pointerof(@data), @length)
end
end
list_ptr = LibList.new_list
p list_ptr.value.to_slice
Interesting, which should I use as a canonical solution? Frankly, now I wonder why declaring the member as a pointer itself doesn't work.
Because it's not a pointer. The array is inlined in the struct. Any of those solutions is fine, there's no canonical way for it.
Maybe we could make it inline with an annotation. Let's leave this open.
If we follow C's semantics, the VLA member will be ignored by sizeof
and assignments, so a closer approximation would be something like:
lib LibList
struct ListT
length : LibC::UInt
data : LibC::Int[0]
end
end
struct LibList::ListT
def to_slice
Slice.new(@data.to_unsafe, @length)
end
end
If there is an annotation for VLA members we could also check for constructs not allowed in C (e.g. VLAs not the end of a lib struct, VLA-containing structs as members of other structs), but that isn't necessary.
Just ran into this for some extern
constants, appears to be the same issue, but @HertzDevil's solution works beautifully.
Update: I seem to be having trouble with getting either @asterite's second solution or @HertzDevil's solution to work with more complex structs (specifically DeviceVersion
and KeyblocksInfo
here), although it works fine with these IndexedString
struct globals.
I was trying to work with a C library that has flexible array members declared in its structs and ran into trouble with using them in a
lib
declaration.Given a hypothetical
list.c
:Trying to treat it as a normal pointer causes a segfault:
Replacing the pointer with
LibC::Int[]
gives a parse failure.crystal --version
: