7

I have a c api that returns a null terminated string that is an array of type unsigned char* (which would correspond to UnsafePointer<UInt8>).

Swift has the initializer String(validatingUTF8:), but the argument has to be UnsafePointer<CChar> (a.k.a. UnsafePointer<Int8>), and there is no trivial way to convert between the two.

How do I convert from this null-terminated c-string to a Swift string?

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
AthanasiusOfAlex
  • 1,290
  • 2
  • 16
  • 23

1 Answers1

14

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.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Got it. It was not appearing in my auto-complete. – AthanasiusOfAlex Sep 16 '16 at 14:23
  • In swift 5.7 with Xcode 14, init(validatingUTF8:... and init(cSting: .... are deprecated :( , any suggestions for this change ? – Ramin Aug 15 '22 at 15:16
  • @Ramin: My suggested `extension String { ... }` code does not use that method, but uses `String.decodeCString()`. Is there a problem with that code? – Martin R Aug 15 '22 at 16:53