Converting a C char array to a String
The C array char name[8]
is imported to Swift as a tuple:
(Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
The address of name
is the same as the address of name[0]
, andSwift preserves the memory layout of structures imported from C, asconfirmed by Apple engineer Joe Groff:
... You can leave the struct defined in C and import it into Swift. Swift will respect C's layout.
As a consequence, we can pass the address of record.name
,converted to an UInt8
pointer, tothe String initializer. The following code has been updated for Swift 4.2 and later:
let record = someFunctionReturningAStructRecord()let name = withUnsafePointer(to: record.name) { $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) { String(cString: $0) }}
NOTE: It is assumed that the bytes in name[]
are a valid NUL-terminated UTF-8 sequence.
For older versions of Swift:
// Swift 2:var record = someFunctionReturningAStructRecord()let name = withUnsafePointer(&record.name) { String.fromCString(UnsafePointer($0))!}// Swift 3:var record = someFunctionReturningAStructRecord()let name = withUnsafePointer(to: &record.name) { $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: record.name)) { String(cString: $0) }}
You can actually collect a tuple into an array by using Swift's variadic parameter syntax:
let record = getRecord()let (int8s: Int8...) = myRecord // int8s is an [Int8]let uint8s = int8s.map { UInt8($0) }let string = String(bytes: uint8s, encoding: NSASCIIStringEncoding)// myString == Optional("12345678")
I'm interested in working this out for my own purposes as well, so I added a new function:
func asciiCArrayToSwiftString(cString:Int8...) -> String{ var swiftString = String() // The Swift String to be Returned is Intialized to an Empty String var workingCharacter:UnicodeScalar = UnicodeScalar(UInt8(cString[0])) var count:Int = cString.count for var i:Int = 0; i < count; i++ { workingCharacter = UnicodeScalar(UInt8(cString[i])) // Convert the Int8 Character to a Unicode Scalar swiftString.append(workingCharacter) // Append the Unicode Scalar } return swiftString // Return the Swift String}
I call this function with:
let t:Int8 = Int8(116) let e:Int8 = Int8(101) let s:Int8 = Int8(115) let testCString = (t, e, s, t) let testSwiftString = wispStringConverter.asciiCArrayToSwiftString(testCString.0, testCString.1, testCString.2, testCString.3) println("testSwiftString = \(testSwiftString)")
the resulting output is:
testSwiftString = test