Swift 3: convert a null-terminated UnsafePointer UInt8 to a string
In Swift 3, String
has two initializers
public init(cString: UnsafePointer<CChar>)
public init(cString: UnsafePointer<UInt8>)
therefore it can be created from (null-terminated) sequences of both signed and unsigned characters. So
let s = String(cString: yourCharPointer)
should just work.
String
has another initializer
public init?(validatingUTF8 cString: UnsafePointer<CChar>)
which fails on ill-formed UTF-8 sequences instead of replacing them
by the replacement characters. This init method has no counterpart
taking unsigned characters.
Taking the existing implementations in CString.swift as examples, it is not too difficult to add this as an extension:
extension String {
public init?(validatingUTF8 cString: UnsafePointer<UInt8>) {
guard let (s, _) = String.decodeCString(cString, as: UTF8.self,
repairingInvalidCodeUnits: false) else {
return nil
}
self = s
}
}
and then
if let s = String(validatingUTF8: yourCharPointer) {
print(s)
} else {
print("invalid UTF-8")
}
also works with (null-terminated) sequences of both signed and unsigned characters.
Issue with UnsafePointer Uint8 in SQLite project in Swift
This should work:
let address = sqlite3_column_text(statement, 0)
let string = String.fromCString(UnsafePointer<CChar>(address))
Update for Swift 3 (Xcode 8), compare Swift 3: convert a null-terminated UnsafePointer<UInt8> to a string:
let string = String(cString: sqlite3_column_text(statement, 0))
Update:
sqlite3_column_text()
returns an implicitly unwrapped optional, and that is why you can pass it to String(cString:)
directly.
But according to Column methods, error and NULL handling #41, the return value can be null (in an out-of-memory situation, or if called with a NULL column type). Therefore it is safer to do
if let text = sqlite3_column_text(statement, 0) {
let string = String(cString: text)
// ...
} else {
// sqlite3_column_text() returned NULL
}
iOS: Convert UnsafeMutablePointer Int8 to String in swift?
If the pointer points to a NUL-terminated C string of UTF-8 bytes, you can do this:
import Foundation
let x: UnsafeMutablePointer<Int8> = ...
// or UnsafePointer<Int8>
// or UnsafePointer<UInt8>
// or UnsafeMutablePointer<UInt8>
let str = String(cString: x)
How to extend String's UnsafePointer Int8 initializer to accept NULL pointers?
That's fine. You have a failable initializer which “fails” (returns nil
) if the given argument is nil
. Otherwise it unwraps the argument and initializes the string by assigning to self
(which can be done with struct
types).
CChar
is indeed the same type as Int8
on all Apple platforms (where char
is a signed character). I would write the argument type as UnsafePointer<CChar>?
to emphasize the connection with the char
type in C.
A (only slightly different) alternative is
extension String {
init?(cString: UnsafePointer<CChar>?) {
guard let cString = cString else { return nil }
self.init(cString: cString)
}
}
but that is purely a matter of taste.
Swift3: Proper way to convert string to null-terminated C-string
don't use unsafeBitCast for that!!
let cstr = "alpha".nulTerminatedUTF8
let int8arr = cstr.map{ Int8(bitPattern: $0) }
let uint8arr = Array(cstr)
print(int8arr.dynamicType, uint8arr.dynamicType)
// Array<Int8> Array<UInt8>
update
let uint8: UInt8 = 200
let int8 = Int8(bitPattern: uint8)
print(uint8, int8)
// 200 -56
String value to UnsafePointer UInt8 function parameter behavior
This is working because of one of the interoperability changes the Swift team has made since the initial launch - you're right that it looks like it hasn't made it into the documentation yet. String
works where an UnsafePointer<UInt8>
is required so that you can call C functions that expect a const char *
parameter without a lot of extra work.
Look at the C function strlen
, defined in "shims.h":
size_t strlen(const char *s);
In Swift it comes through as this:
func strlen(s: UnsafePointer<Int8>) -> UInt
Which can be called with a String
with no additional work:
let str = "Hi."
strlen(str)
// 3
Look at the revisions on this answer to see how C-string interop has changed over time: https://stackoverflow.com/a/24438698/59541
Convert an array of CChar to Hexa String in Swift
What you are looking for is the Swift cString initializer:
init(cString: UnsafePointer<CChar>)
If cString contains ill-formed UTF-8 code unit sequences, this
initializer replaces them with the Unicode replacement character
("\u{FFFD}").
let buff: [CChar] = [97, 98, 99, 0] // null-terminated string
let string: String = .init(cString: buff)
print(string) // "abc\n"
edit/update:
To convert from [CChar] to hexaString you would need to map your bitPattern and use String format: "%02x" to convert the bytes to hexa:
let buff: [CChar] = [56, 54, 45, -103, 95, -59]
let hexaString = buff.map {
String(format: "%02x", UInt8(bitPattern: $0))
}.joined()
print(hexaString) // "38362d995fc5\n"
UnsafePointer Int8 not working
In
let ua = UnsafePointer<Int8>(a)
the
init(_ other: UnsafePointer<Pointee>)
initializer of UnsafePointer
is called. I.e. you are passing
a Swift String
to a function taking a UnsafePointer<Int8>
argument. In that case a temporary C string representation is created and passed to the function,
compare String value to UnsafePointer<UInt8> function parameter behavior.
That temporary C string is only valid for the duration of the function
call, and on return, it is not guaranteed that the memory pointed
to by ua
still contains that C string (or any valid data). In addition,
let ua = UnsafePointer<Int8>(a)
let ub = UnsafePointer<Int8>(b)
let uc = UnsafePointer<Int8>(c)
can use the same storage for the temporary C string, in that case
the pointers would be equal, as you observed.
If your intention is to call a C function taking const char *
arguments, then you can simply pass the Swift strings. The compiler
will insert the necessary code to create C string representations
(which are again valid for the duration of the function call),
as explained in String value to UnsafePointer<UInt8> function parameter behavior:
let a = "aaa"
let b = "bbb"
let c = "ccc"
cfunc(a, b, c)
Related Topics
Difference Between String Interpolation and String Initializer in Swift
Rxswift Merge Different Kind of Observables
Can the Conversion of a String to Data with Utf-8 Encoding Ever Fail
Convert a Custom Object to Data to Be Saved in Nsuserdefauts
Could Not Find an Overload for '^' That Accepts the Supplied Arguments
How to Detect Vertical Planes in Arkit
How to Auto Clear Nsuserdefault Values in Swift
Present Uiviewcontroller as a Modal with Transparent Background
How to Hide Labels in iOS-Charts
How to Create Nsradiobutton Group in Xcode 7 Osx
Swift 2 Protocol Extension Not Calling Overridden Method Correctly
Swift String Interpolation Displaying Optional
How to Handle Closure Recursivity
Swift Http Request Use Urlsession
Find Nearest Smaller Number in Array
Lazy Loading Properties in Swift