Best way to represent C struct pointer in Swift?

It seems that Swift works nicely with basic C types and C structs.
But what is the recommended way to deal with struct pointers?
Should I convert part of it to a plain struct and use a void* for the private stuff that is off-limits to the Swift code?

e.g.
typedef struct { int foo, bar; void* private; } Thing;
// in Swift:
let thing= Thing();

Or:
typedef struct { int foo, bar; void* private; } Thing;
typedef Thing *ThingRef;
// then in Swift
let thing = ThingRef()?

Or will Swift choke on the void*?

Swift has no problem with void *: it becomes UnsafeMutableRawPointer. How you represent this is really a matter for API design. I will say that if you do typedef Thing *ThingRef then ThingRef() will not be a line of code you can actually write. You’d need to do ThingRef.allocate(capacity: 1).

It’s hard to work idiomatically with C opaque struct pointers in Swift. You can certainly do it but it’s inherently unsafe (in the Swift sense of unsafe), and it’s best not to let that unsafeness spread throughout your codebase.

Personally I solve this problem by wrapping the C opaque struct pointer with a Swift class. This is reference counted, and thus avoids the biggest pitfalls.

Pasted in below is a short example.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple


import Foundation
import libxml2

class XMLWriter {

    private let writer: xmlTextWriterPtr

    init(destination: URL) throws {
        guard let w = xmlNewTextWriterFilename(destination.path, 0) else {
            // … throw the error …
        }
        self.writer = w
    }

    deinit {
        xmlFreeTextWriter(self.writer)
    }

    func startElement(named name: String) throws {
        let didFail = xmlTextWriterStartElement(self.writer, name) < 0
        // … throw the error …
    }

    // … and so on …
}
1 Like

In my case things are a little different:
Swift is allowed to use C structs of type Fubar, however the allocation and deallocation of them is done by the FubarManager which is written in C.
For this reason I've gone down the path of letting Swift using Fubar structs as plain old structs, not as pointers to structs. But I worry about this approach-- I don't want to run up against any brick walls.
FYI, I can't rewrite FubarManager in Swift.

however the allocation and deallocation of them is done by the FubarManager which is written in C.

In this case you dont want to allocate the structs on Swift side, because you will have lifetimes problems.

If you allocate a struct inside swift you must remember its stack allocated the same way as in C, so as soon its out of scope the struct will be deallocated!

Make your 'FubarManager' allocate them on the C side and only return a opaque handle 'void*' in C and 'UnsafeRawMutablePointer?' in Swift.

Do as Skimo is showing.. you get the handle allocated on the C side with something like "let ref = CFubarNew()" and wrap it (the opaque handle) inside a class using the deinit to call your C destructor "CFubarDestroy(ref)"

Manage the allocation in C but you still have the lifetime bounded on Swift side so:

"{
let fubar = Fubar()
fubar.something()
}"

will get automatically deallocated once the Swift ARC triggers

Terms of Service

Privacy Policy

Cookie Policy