I have a problem with the String.withCString{} in combination with UnsafeMutablePointer(mutating: ...).
Given: a C-Function like this
randomSign(xml_string: UnsafeMutablePointer<Int8>!) -> Uint
Also given: a String like
str = "some xml_tag"
My working code is like this (VERSION_1)
func randomSignWrapper_1(xml_tag_str: String) -> Uint {
let result = xml_str.withCString { s in return
randomSign(UnsafeMutablePointer(mutating: s))
}
return result
}
But I want the withCString to be put into a separate function like this:
func testFunction(_ x: String) -> UnsafeMutablePointer<Int8>{
return x.withCString{s in
return UnsafeMutablePointer(mutating: s)
}
}
So that I can easily reuse it (VERSION_2)
func randomSignWrapper_2(xml_tag_str: String) -> Uint {
let result = randomSign(testFunction(xml_tag_str))
return result
}
But the problem is that VERSION_1 delivers the right return value while VERSION_2 is somehow not working properly, and telling me that the data is wrong. And I would like to know why it behaves like this? And how to solve it that I can use it the described way?
Check the reference of
withCString(_:)
.Your VERSION_2 code is trying to escape it from the closure for later use. It's not a valid usage of
withCString(_:)
.The region containing UTF-8 representation of the
String
is temporal and Swift runtime will release it at any time.You can write something like this:
But I wonder if you need to define a function like
utf8Array(from:)
.withCString { ... }
creates a temporary representation of the Swift string as null-terminated UTF-8 sequence, which is valid only inside the closure. Passing the pointer to the outside of the closure is undefined behaviour.Also note that you cannot mutate the string using that pointer. Passing
UnsafeMutablePointer(mutating: $0)
only makes the compiler believe that the pointed-to memory is mutable, but actually doing so is undefined behaviour and might even crash.If
randomSign()
function does not modify the given string then the best solution is to change its C declaration to take a constant string:This would be imported to Swift as
Now you can pass a Swift string directly to that function:
The compiler automatically inserts the code for creating a temporary UTF-8 representation and passing that to the function, compare String value to UnsafePointer<UInt8> function parameter behavior.
If you cannot change the C declaration then you still can call it asalso without the need for your own helper function.
Update: The last suggestion is not correct. The temporary string created by the compiler is only during for the call of
UnsafeMutablePointer()
but not necessarily still valid during the call ofrandomSign()
.