検証環境
Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1)
Target: x86_64-apple-darwin17.6.0
TL;DR;
SwiftのStringからC用の文字列を生成するには、utf8CString
プロパティから生成するのがベスト・プラクティスだと思われます。
SwiftにおけるC文字列を表す型
SwiftにてUTF8用のCの文字列を表す型は以下があります。
- UnsafePointer<CChar>
- UnsafeMutablePointer<CChar>
- UnsafePointer<UInt8>
- UnsafeMutablePointer<UInt8>
Note: CChar = Int8
Foundationを使わずに、上記の型を生成するためのベスト・プラクティスを考えてみました。
StringからC文字列への変換に使用するプロパティ
Cの文字列には終端を意味する null文字 を最後につける必要があります。
しかしながら、 utf8 プロパティで生成される String.UTF8View
の要素内には、null文字が含まれません。
なのでnull終端文字が含まれる utf8CString プロパティを使用します。
utf8.swift
let s = "Hello!"
let bytes = Array(s.utf8)
print(bytes)
// Prints "[72, 101, 108, 108, 111, 33]"
utf8cstring.swift
let s = "Hello!"
let bytes = s.utf8CString
print(bytes)
// Prints "[72, 101, 108, 108, 111, 33, 0]" 最後にnull終端文字の0が含まれる
String to cString
UnsafeMutablePointer<CChar> の生成
utf8CString
プロパティで生成される配列の要素の型が CChar
なので、配列をそのままUnsafePointerに変換して生成します。
Note: CChar = Int8
string2cstring_int8.swift
func makeCString(from str: String) -> UnsafeMutablePointer<Int8> {
let count = str.utf8CString.count
let result: UnsafeMutableBufferPointer<Int8> = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
// func initialize<S>(from: S) -> (S.Iterator, UnsafeMutableBufferPointer<Element>.Index)
_ = result.initialize(from: str.utf8CString)
return result.baseAddress!
}
// EXAMPLE
let str = "朝日がさんさん おはよ〜お〜さ〜ん 🌟 Good morning everyone! 👪"
let cstr = makeCString(from: str)
let restr = String(cString: cstr)
print(str == restr) // true
UnsafeMutablePointer<UInt8> の生成
utf8cstring で生成される配列の要素の型が CChar なので、 withMemoryRebound
メソッドを使って、要素の中身を UInt8 にキャストします。
Note: CChar = Int8
string2cstring_uint8.swift
func makeCString(from str: String) -> UnsafeMutablePointer<UInt8> {
let utf8 = str.utf8CString
let count = utf8.count
let result = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: count)
_ = utf8.withUnsafeBufferPointer { baseAddress in
// 要素の中身を CChar から UInt8 にキャストする
baseAddress.withMemoryRebound(to: UInt8.self) { baseAddress2 in
// baseAddress2: UnsafeMutableBufferPointer<UInt8>
result.initialize(from: baseAddress2)
}
}
return result.baseAddress!
}
Appendix utf8プロパティからの生成
utf8 プロパティからC文字列を生成する場合は、null文字を追加すれば問題ありません。
string2cstring.swift
// UnsafeMutablePointer<UInt8>
func makeCString(from str: String) -> UnsafeMutablePointer<UInt8> {
var utf8 = Array(str.utf8)
utf8.append(0) // adds null character
let count = utf8.count
let result = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: count)
_ = result.initialize(from: utf8)
return result.baseAddress!
}
// UnsafeMutablePointer<Int8>
func makeCString(from str: String) -> UnsafeMutablePointer<Int8> {
var utf8 = Array(str.utf8)
utf8.append(0) // adds null character
let count = utf8.count
let result = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
utf8.withUnsafeBufferPointer { baseAddress in
baseAddress.withMemoryRebound(to: Int8.self) { (baseAddress2) in
_ = result.initialize(from: baseAddress2)
}
}
return result.baseAddress!
}