Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert String to UnsafeMutablePointer<char_t> in Swift

Tags:

swift

cstring

I'm working with a third party c API I'm trying to call one of the functions with a simple string. Something like this:

some_c_func("aString");

I get a build error:

Type 'UnsafeMutablePointer<char_t>' does not conform to protocol 'StringLiteralConvertible'

I've seen some suggestions to use utf8 on String or similar conversions, which gets nearly there, but with the following error:

some_c_func("aString".cStringUsingEncoding(NSUTF8StringEncoding));
'UnsafePointer<Int8>' is not convertible to 'UnsafeMutablePointer<char_t>'

How can I create an UnsafeMutablePointer?

like image 801
brodney Avatar asked Sep 29 '22 02:09

brodney


2 Answers

It all depends on what char_t is.

If char_t converts to Int8 then the following will work.

if let cString = str.cStringUsingEncoding(NSUTF8StringEncoding) {
    some_c_func(strdup(cString))
}

This can be collapsed to

some_c_func(strdup(str.cStringUsingEncoding(NSUTF8StringEncoding)!))

WARNING! This second method will cause a crash if func cStringUsingEncoding(_:) returns nil.


Updating for Swift 3, and to fix memory leak

If the C string is only needed in a local scope, then no strdup() is needed.

guard let cString = str.cString(using: .utf8) else {
    return
}

some_c_func(cString)

cString will have the same memory lifecycle as str (well similar at least).

If the C string needs to live outside the local scope, then you will need a copy. That copy will need to be freed.

guard let interimString = str.cString(using: .utf8), let cString = strdup(interimString) else {
    return
}

some_c_func(cString)

//…

free(cString)
like image 113
Jeffery Thomas Avatar answered Nov 15 '22 08:11

Jeffery Thomas


it may be simpler than that - many C APIs pass strings around as char * types, and swift treats these as unsafe.

try updating the C API (good) or hack it's header files (bad) to declare these as const char * instead.

in my experience this allows you to pass standard swift String types directly to the C API.

apparently a constant is required, in order to conform to the protocol.

like image 21
rewindustry Avatar answered Nov 15 '22 08:11

rewindustry