How to Convert a String to a Cstring in the Swift Language

How do you convert a String to a CString in the Swift Language?

You can get a CString as follows:

import Foundation

var str = "Hello, World"

var cstr = str.bridgeToObjectiveC().UTF8String

EDIT: Beta 5 Update - bridgeToObjectiveC() no longer exists (thanks @Sam):

var cstr = (str as NSString).UTF8String

Passing a Swift string to C

The Swift equivalent of const char * is UnsafePointer<CChar>?, so that's the correct return value. Then you have to think about memory management. One options is do allocate memory for the C string in the Swift function, and leave it to the caller to release the memory eventually:

public func mySwiftFunc(number: Int) -> UnsafePointer<CChar>? {
print("Hello from Swift: \(number)")

let address = "hello there"
let newString = strdup(address)
return UnsafePointer(newString)
}

passes a Swift string to strdup() so that a (temporary) C string representation is created automatically. This C string is then duplicated. The calling C function has to release that memory when it is no longer needed:

int blah() {
const char *retVal = mySwiftFunc(42);
printf("Hello from C: %s\n", retVal);
free((char *)retVal);
return 0;
}

⚠️ BUT: Please note that there are more problems in your code:

  • mySwiftFunc() is an instance method of a class, and therefore has an implicit self argument, which is ignored by the calling C function. That might work by chance, or cause strange failures.
  • @_silgen_name should not be used outside of the Swift standard library, see this discusssion in the Swift forum.
  • A slightly better alternative is @_cdecl but even that is not officially supported. @_cdecl can only be used with global functions.
  • Generally, calling Swift functions directly from C is not officially supported, see this discussion in the Swift forum for the reasons and possible alternatives.

Swift String to CChar

You can convert a Swift string to a Cstring and then just grab the first (and only) character:

var charString = "a"
var ccharOptional = charString.cStringUsingEncoding(NSUTF8StringEncoding)?[0] // CChar?
var cchar = (charString.cStringUsingEncoding(NSUTF8StringEncoding)?[0])! // CChar

Working with C strings in Swift, or: How to convert UnsafePointer CChar to CString

Swift 1.1 (or perhaps earlier) has even better C string bridging:

let haystack = "This is a simple string"
let needle = "simple"
let result = String.fromCString(strstr(haystack, needle))

The CString type is gone completely.

Convert Swift string into CChar pointer

If the C function does not mutate the strings passed as arguments,
then the parameters should be declared as const char *,
for example

int func1(const char *s1, const char *s2);

and in that case you can simply pass Swift strings which are automatically converted (compare String value to UnsafePointer<UInt8> function parameter behavior):

let str1 = "first string argument"
let str2 = "second string argument"

let result1 = func1(str1, str2)

If the function parameters are declared as char *

int func2(char *s1, char *s2);

then you have to use withCString() to obtain a temporary representation
of the string as a NUL-terminated array of UTF-8 characters:

let str1 = "first string argument"
let str2 = "second string argument"

// Swift 2:
let result2 = str1.withCString { s1 in
str2.withCString { s2 in
func2(UnsafeMutablePointer(s1), UnsafeMutablePointer(s2))
}
}

// Swift 3:
let result2 = str1.withCString { s1 in
str2.withCString { s2 in
func2(UnsafeMutablePointer(mutating: s1), UnsafeMutablePointer(mutating: s2))
}
}

Note that this still assumes that the function does not mutate the
passed strings, the UnsafeMutablePointer() conversion is only
needed to make the compiler happy.

CMutablePointer CString to String in swift-language

It goes something like:

 var stringValue :CString = ""

 name.withUnsafePointer {p in
stringValue = p.memory
}

return NSString(CString: stringValue)

Convert String to UnsafeMutablePointer char_t in Swift

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)

Converting a C string inside a struct to a Swift String

Well, at least that C character array is only eight characters long, since there's currently no way to iterate over a tuple. Here's how you can convert it:

func char8ToString(tuple: (CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar)) -> String {
let arr: unichar[] = [unichar(tuple.0), unichar(tuple.1),
unichar(tuple.2), unichar(tuple.3),
unichar(tuple.4), unichar(tuple.5),
unichar(tuple.6), unichar(tuple.7)]
let len = arr.reduce(0) { $1 != 0 ? $0 + 1 : $0 }
return NSString(characters: arr, length: len)
}

var manufacturer: String = char8ToString(cycle.mfg)

Hopefully we get language support for a better way to handle this case soon!



Related Topics



Leave a reply



Submit