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 implicitself
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
Using Stringbyreplacingcharactersinrange in Swift
Higher Order Function: "Cannot Invoke 'Map' with an Argument List of Type '((_) -> _)'"
Swift 4.0 Mapview Running Slow
Implicit Return in a Closure Causing an Error
How to Make Keyboard Dismiss When I Press Out of Searchbar on Swift
Checking If a Value Is Changed Using Kvo in Swift 3
Which Format File for 3D Model Scenekit/Arkit Better to Use
Rotate an Object in Its Direction of Motion
Bool Being Seen as Int When Using Anyobject
How to Write Inline Assembly in Swift
Getting String Name of Objective-C @Objc Enum Value in Swift
Unexpectedly Large Realm File Size
Function Throws and Returns Optional.. Possible to Conditionally Unwrap in One Line
Ambiguous Use of Subscript (Swift 3)
How to Assign an Optional Binding Parameter in Swiftui
How to Conform to Nscopying and Implement Copywithzone in Swift 2
In Swift, How to Get Memory Back to Normal After an Skscene Is Removed