QB64-Phoenix-Edition / QB64pe

The QB64 Phoenix Edition Repository
https://qb64phoenix.com
Other
131 stars 26 forks source link

Allow UTD variables to be passed to external functions by value #342

Open a740g opened 1 year ago

a740g commented 1 year ago

QB64-PE currently does not support passing UTD variables to external functions by value.

For example, we can write:

TYPE Vector2
    x AS SINGLE
    y AS SINGLE
END TYPE

DECLARE STATIC LIBRARY "./my_math"
    FUNCTION Distance! (BYVAL p1 AS Vector2, BYVAL p2 AS Vector2)
END DECLARE

DIM AS Vector2 pa, pb: pa.x = 10: pa.y = 10: pb.x = 100: pb.y = 100

PRINT Distance(pa, pb)

However, this gives an error: User defined types in expressions are invalid on the current line.

This IMO is a problem, and it makes working with external C libraries and other OS APIs difficult and cumbersome.

Also see #30. This too impacts working with external libraries which return UDTs by value instead of pointers.

mkilgore commented 1 year ago

One problem here is that in the generated code UDTs are just char arrays, and you can't pass a char array like a struct. I'm not entirely sure how we get around that, we could just declare a struct { char foo[x] } for a struct of size x and pass that, but I'm not sure the semantics of how passing structs by value works and whether that would be reliable (certainly it's a no-no, we wouldn't be passing the right type of struct. Depending on how the struct is passed to the function it may or may not work at all though).

a740g commented 1 year ago

Well, that is certainly a problem. I could work around this by writing C wrappers that take a pointer to the UDT and then deference it and pass it to the library function (which mostly worked). However, QB64 does not do any member alignment for TYPES if the type itself is just an array of chars. This caused all kinds of trouble. Ultimately, I had to do a LEN(x) and sizeof(x) comparison of the structs I was using and then manually add padding to the TYPEs to fix the alignments and sizes. Everything worked after I did this. However, this is certainly not an easy or a portable solution.