Convert String to UnsafeMutablePointer<Int8>


(David Hart) #1

How can I convert a String to a UnsafeMutablePointer<Int8> for passing to a non-const C API?


(Jordan Rose) #2

Does the C API actually mutate the buffer? If so, I don't think there's currently a safe way to do this that doesn't require copying:

var buffer = Array(str.utf8)
buffer.append(0)
importedCFunction(&buffer)
let newString = String(cString: buffer)

If the C API doesn't mutate the buffer and is just declared wrong suboptimally, you can reinterpret the pointer and cross your fingers:

str.withCString {
  importedCFunction(UnsafeMutablePointer(mutating: $0))
}

(David Hart) #3

Thanks! I’m surprised about the first answer. I was hoping there was a cStringCopy function. Would that be an inteeesting addition to the Standard Library?


(Ben Cohen) #4

I don't know if there's enough call for such an API to justify adding it.

I think the reason @jrose questioned whether the API truly mutated the buffer is that actually-mutating C string APIs are unusual, because they're a bit weird. With Unicode strings, almost any mutation ends up needing to resize the string, which introduces all sorts of complications (you need to pass before/after lengths and capacities back and forth). Giving mutating access to a String's underlying buffer could also break invariants or perf flags, like normalization or ascii-ness, that the String might be preserving.


(Jordan Rose) #5

Also, if you admit to working in C-string-land, strdup is perfectly callable from Swift. But then you have to remember to free the result yourself, which is why I used Array instead.


(Ben Cohen) #6

Array also has the future potential of being convertible back to a String type at no cost, via some of the ideas outlined in this post. This would mitigate some of the performance downsides of operating "outside" of the string type.