10

I would like to constrain a generic to a type that can be represented in C. Is there a protocol or type in the Swift standard library that all C types conform to?

func doWithCType<T:CRepresentable>(cValue: T) {
    // do thing with C type
}

If not a CRepresentable, maybe a CStruct type?

Clues:

Using this C type:

typedef struct {
    int hodor;
} Hodor;

I force casted a struct to an incompatible type (causing a crash). This was the error message: Could not cast value of type '__C.Hodor' (0x1035c0700) to 'Swift.CVarArg' (0x107196240).

I can't find "__C" anywhere, but I'm hopeful that there's a distinction for the C types.

dave234
  • 4,793
  • 1
  • 14
  • 29
  • What do you consider "a type representable in C"? Anything can be represented in C as raw memory... Plain datatypes? – Itai Ferber Dec 09 '17 at 06:25
  • A c type like a struct or an int that can be accepted as an argument to a C function. I’m hoping to avoid the void* route. – dave234 Dec 09 '17 at 06:28
  • I’m trying to make a Swift/C message queue. – dave234 Dec 09 '17 at 06:29
  • There's no such native protocol in Swift — you'd have to create it yourself. What are you trying to do here though? Once you have something constrained to `CRepresentable`, how do you intend to pass it to C anyway? C can't currently call Swift, but Swift can call into C; in order to pass things to C, you're going to need to know the concrete type to match the calling convention of C. You might be better served with overloads of `doWithCType(cValue:)` (e.g. one for `Int`, one for `Double`, etc.) rather than a generic function. – Itai Ferber Dec 09 '17 at 06:36
  • So the idea is to define a struct in C, then pass the struct to ring buffer in C. The generic in swift is used to define the type that the queue will accept in the swift layer to avoid all the unsafe casting. Ultimately it’s meant as a convenience. – dave234 Dec 09 '17 at 06:42
  • To clarify, I just used a generic function for brevity, really it would be a generic class. – dave234 Dec 09 '17 at 06:48
  • 1
    Related: https://stackoverflow.com/questions/43920260/require-associatedtype-to-be-representable-in-a-conventionc-block – Cristik Sep 18 '19 at 07:53

1 Answers1

5

Is Swift.CVarArg what you need? It is for types that can be passed through C's va_list mechanism for varargs.

There is also CVaListPointer, which is equivalent to va_list *. That appears in the arguments to String(format:).

https://developer.apple.com/documentation/swift/cvararg https://developer.apple.com/documentation/swift/cvalistpointer

Ewan Mellor
  • 6,747
  • 1
  • 24
  • 39
  • Swift.CVarArg is actually what I was trying to cast to that caused the crash. I'll edit my answer to reflect this. – dave234 Dec 09 '17 at 18:23
  • I think if you want to pass structs between C and Swift you're going to end up with `UnsafeMutablePointer` or `COpaquePointer` in your API. c.f. https://modocache.io/swift-and-c. – Ewan Mellor Dec 09 '17 at 18:36
  • I'm going to end up casting to void* in the end, but I'm hoping to contain that casting in one function in a generic. The idea is to create a Swift interface to a C message queue. C can't use swift memory so I was hoping that there was a "C type" constraint. Otherwise It'll come down to relying on documentation to enforce the C types. – dave234 Dec 09 '17 at 18:45