2

In Swift, when calling C functions Swift strings are auto-coerced to CString when passed as parameters. However, I don't get the same behavior when filling out C structs or globals.

strlen(swiftString)                     //Works!
CGlobalStruct.stringPtr = swiftString   //Doesn't work!

First, Why do they behave different when they are both "const *char". Second, what is the cleanest way to fill out C Structs?

1 Answer 1

5

A Swift String can be passed as an argument to a function taking a UnsafePointer<Int8> parameter. The compiler generates a temporary representation of the Swift string as a NUL-terminated sequence of char and passes a pointer to that C String to the function. The representation and the pointer is only valid during the function call. That is what happens at

strlen(swiftString)   

When assigning a global C string pointer then you have to take the lifetime of this pointer into account. One possibility is

let swiftString = "Hello world"

swiftString.withCString {
    CGlobalStruct.stringPtr = $0

    // Pointer valid inside this closure ...
}
// Pointer not valid anymore ...

where a pointer to a C string representation is passed to the closure. This pointer is (only) valid during the execution of the closure.

For longer-lived usage you could allocate a C string in memory, but then you are responsible for freeing that memory eventually:

guard let cStringPtr = strdup(swiftString) else {
    fatalError("strdup failed")
}
CGlobalStruct.stringPtr = UnsafePointer(cStringPtr)

// ...

free(cStringPtr)
Sign up to request clarification or add additional context in comments.

2 Comments

Very thoughtful response. The bridging of swift to c is quite good in most places, but if this is as good as it gets for assigning swift string literals to C structs... its kind of gross (not to mention obscure). Compare to the simplicity of bridging other types like CGlobalStruct.integer = 45
@TroyHarvey: Integers are "simple" types and have the same memory representation in C and Swift. A Swift String is a struct with opaque pointers to some backing store which can hold bytes (for pure ASCII strings) or UTF-16 code units, and is memory managed by Swift, whereas C strings are NUL-terminated sequences of chars. There is no simple bridging between them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.