How to define structures that can be passed to C?

c-interop
(Miguel De Icaza) #1

Hello,

I would like to invoke a function that I dynamically loaded with dlopen, and I need to pass data to it. Ideally, I could define a structure, and then pass a pointer to the structure to this function, but I have not found a way to express this in Swift.

In C# I can place the [StructLayout(LayoutKind.Sequential)] on a struct, and then the struct becomes blittable and I can pass a pointer to C functions.

The following declaration shows what I am trying to do:

    struct myType {
        var a, b, c: Int32
        var d: Int8
    }
    // This is wrong
    typealias add_wch_def = @convention(c) (UnsafeMutablePointer<myType>) -> CInt

When I compile that, I get:

'(UnsafeMutablePointer<CursesDriver.myType>) -> CInt' (aka '(UnsafeMutablePointer<CursesDriver.myType>) -> Int32') is not representable in Objective-C, so it cannot be used with '@convention(c)'

Any guidance as to what I could try in this scenario?

(Joe Groff) #2

You can define the type in C, say by putting it your bridging header.

2 Likes
(Steve Canon) #3

And, in fact, defining it in a C header is the only officially supported way to do this.

3 Likes
(Ole Begemann) #4

This April 2017 quote from @John_McCall suggests tuples can be used for this purpose:

Is this advice this correct?

1 Like
(John McCall) #5

Yes; the layout of a tuple is guaranteed to be the basic in-order rounding-to-alignment layout. We don’t guarantee that primitive type alignments will match C in all cases, but if you have a tuple with no need for alignment padding, it should have the obvious layout.

4 Likes
(Steve Canon) #6

Everything John said is absolutely correct, but: you should still define the structure in a C header that you import, because that way you have a single definition for the layout, rather than two separate definitions that you need to keep in sync if you make changes. One of Swift's big strengths that doesn't get talked about much is its ability to import C API without futzing with memory layout or calling-convention details. Use the C API directly if you can.

8 Likes
(Miguel de Icaza) #7

Thanks for all the details, this is super useful.

I found that the C header worked great. Very smooth. Not sure if this will work once I try this on other platforms, but for now I am unblocked.

Thanks!