Swift 3: Convert a Null-Terminated Unsafepointer<Uint8> to a String

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



Leave a reply



Submit